From 5ae1cb7220827de24b96b620dc61eb29408edfb7 Mon Sep 17 00:00:00 2001 From: Anyon Date: Mon, 7 Mar 2022 14:42:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20lay=5Fcascader=20=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/static/plugs/layui_exts/cascader.css | 1654 +++++++++++++++ public/static/plugs/layui_exts/cascader.js | 2085 +++++++++++++++++++ 2 files changed, 3739 insertions(+) create mode 100644 public/static/plugs/layui_exts/cascader.css create mode 100644 public/static/plugs/layui_exts/cascader.js diff --git a/public/static/plugs/layui_exts/cascader.css b/public/static/plugs/layui_exts/cascader.css new file mode 100644 index 000000000..2997f818c --- /dev/null +++ b/public/static/plugs/layui_exts/cascader.css @@ -0,0 +1,1654 @@ +.el-cascader-panel .layui-icon, .el-cascader .layui-icon { + font-size: 12px; +} + +/* layui表单验证不通过颜色 */ +.layui-form-danger + .el-cascader .el-input__inner { + border-color: #FF5722 !important; +} + +/* 在layui表单中宽度自动撑满 */ +.layui-form .el-cascader { + width: 100%; +} + +/*弹出面板*/ +.el-popper .popper__arrow, .el-popper .popper__arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid +} + +.el-popper .popper__arrow { + border-width: 6px; + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .03)) +} + +.el-popper .popper__arrow:after { + content: " "; + border-width: 6px +} + +.el-popper[x-placement^=top] { + margin-bottom: 12px +} + +.el-popper[x-placement^=top] .popper__arrow { + bottom: -6px; + left: 50%; + margin-right: 3px; + border-top-color: #ebeef5; + border-bottom-width: 0 +} + +.el-popper[x-placement^=top] .popper__arrow:after { + bottom: 1px; + margin-left: -6px; + border-top-color: #fff; + border-bottom-width: 0 +} + +.el-popper[x-placement^=bottom] { + margin-top: 12px +} + +.el-popper[x-placement^=bottom] .popper__arrow { + top: -6px; + left: 50%; + margin-right: 3px; + border-top-width: 0; + border-bottom-color: #ebeef5 +} + +.el-popper[x-placement^=bottom] .popper__arrow:after { + top: 1px; + margin-left: -6px; + border-top-width: 0; + border-bottom-color: #fff +} + +.el-popper[x-placement^=right] { + margin-left: 12px +} + +.el-popper[x-placement^=right] .popper__arrow { + top: 50%; + left: -6px; + margin-bottom: 3px; + border-right-color: #ebeef5; + border-left-width: 0 +} + +.el-popper[x-placement^=right] .popper__arrow:after { + bottom: -6px; + left: 1px; + border-right-color: #fff; + border-left-width: 0 +} + +.el-popper[x-placement^=left] { + margin-right: 12px +} + +.el-popper[x-placement^=left] .popper__arrow { + top: 50%; + right: -6px; + margin-bottom: 3px; + border-right-width: 0; + border-left-color: #ebeef5 +} + +.el-popper[x-placement^=left] .popper__arrow:after { + right: 1px; + bottom: -6px; + margin-left: -6px; + border-right-width: 0; + border-left-color: #fff +} + +.el-tag { + background-color: #ecf5ff; + display: inline-block; + height: 32px; + padding: 0 10px; + line-height: 30px; + font-size: 12px; + color: #409eff; + border: 1px solid #d9ecff; + border-radius: 4px; + box-sizing: border-box; + white-space: nowrap +} + +.el-tag.is-hit { + border-color: #409eff +} + +.el-tag .el-tag__close { + color: #409eff +} + +.el-tag .el-tag__close:hover { + color: #fff; + background-color: #409eff +} + +.el-tag.el-tag--info { + background-color: #f4f4f5; + border-color: #e9e9eb; + color: #909399 +} + +.el-tag.el-tag--info.is-hit { + border-color: #909399 +} + +.el-tag.el-tag--info .el-tag__close { + color: #909399 +} + +.el-tag.el-tag--info .el-tag__close:hover { + color: #fff; + background-color: #909399 +} + +.el-tag.el-tag--success { + background-color: #f0f9eb; + border-color: #e1f3d8; + color: #67c23a +} + +.el-tag.el-tag--success.is-hit { + border-color: #67c23a +} + +.el-tag.el-tag--success .el-tag__close { + color: #67c23a +} + +.el-tag.el-tag--success .el-tag__close:hover { + color: #fff; + background-color: #67c23a +} + +.el-tag.el-tag--warning { + background-color: #fdf6ec; + border-color: #faecd8; + color: #e6a23c +} + +.el-tag.el-tag--warning.is-hit { + border-color: #e6a23c +} + +.el-tag.el-tag--warning .el-tag__close { + color: #e6a23c +} + +.el-tag.el-tag--warning .el-tag__close:hover { + color: #fff; + background-color: #e6a23c +} + +.el-tag.el-tag--danger { + background-color: #fef0f0; + border-color: #fde2e2; + color: #f56c6c +} + +.el-tag.el-tag--danger.is-hit { + border-color: #f56c6c +} + +.el-tag.el-tag--danger .el-tag__close { + color: #f56c6c +} + +.el-tag.el-tag--danger .el-tag__close:hover { + color: #fff; + background-color: #f56c6c +} + +.el-tag .el-icon-close { + border-radius: 50%; + text-align: center; + position: relative; + cursor: pointer; + font-size: 12px; + height: 16px; + width: 16px; + line-height: 16px; + vertical-align: middle; + top: -1px; + right: -5px +} + +.el-tag .el-icon-close:before { + display: block +} + +.el-tag--dark { + background-color: #409eff; + color: #fff +} + +.el-tag--dark, .el-tag--dark.is-hit { + border-color: #409eff +} + +.el-tag--dark .el-tag__close { + color: #fff +} + +.el-tag--dark .el-tag__close:hover { + color: #fff; + background-color: #66b1ff +} + +.el-tag--dark.el-tag--info { + background-color: #909399; + border-color: #909399; + color: #fff +} + +.el-tag--dark.el-tag--info.is-hit { + border-color: #909399 +} + +.el-tag--dark.el-tag--info .el-tag__close { + color: #fff +} + +.el-tag--dark.el-tag--info .el-tag__close:hover { + color: #fff; + background-color: #a6a9ad +} + +.el-tag--dark.el-tag--success { + background-color: #67c23a; + border-color: #67c23a; + color: #fff +} + +.el-tag--dark.el-tag--success.is-hit { + border-color: #67c23a +} + +.el-tag--dark.el-tag--success .el-tag__close { + color: #fff +} + +.el-tag--dark.el-tag--success .el-tag__close:hover { + color: #fff; + background-color: #85ce61 +} + +.el-tag--dark.el-tag--warning { + background-color: #e6a23c; + border-color: #e6a23c; + color: #fff +} + +.el-tag--dark.el-tag--warning.is-hit { + border-color: #e6a23c +} + +.el-tag--dark.el-tag--warning .el-tag__close { + color: #fff +} + +.el-tag--dark.el-tag--warning .el-tag__close:hover { + color: #fff; + background-color: #ebb563 +} + +.el-tag--dark.el-tag--danger { + background-color: #f56c6c; + border-color: #f56c6c; + color: #fff +} + +.el-tag--dark.el-tag--danger.is-hit { + border-color: #f56c6c +} + +.el-tag--dark.el-tag--danger .el-tag__close { + color: #fff +} + +.el-tag--dark.el-tag--danger .el-tag__close:hover { + color: #fff; + background-color: #f78989 +} + +.el-tag--plain { + background-color: #fff; + border-color: #b3d8ff; + color: #409eff +} + +.el-tag--plain.is-hit { + border-color: #409eff +} + +.el-tag--plain .el-tag__close { + color: #409eff +} + +.el-tag--plain .el-tag__close:hover { + color: #fff; + background-color: #409eff +} + +.el-tag--plain.el-tag--info { + background-color: #fff; + border-color: #d3d4d6; + color: #909399 +} + +.el-tag--plain.el-tag--info.is-hit { + border-color: #909399 +} + +.el-tag--plain.el-tag--info .el-tag__close { + color: #909399 +} + +.el-tag--plain.el-tag--info .el-tag__close:hover { + color: #fff; + background-color: #909399 +} + +.el-tag--plain.el-tag--success { + background-color: #fff; + border-color: #c2e7b0; + color: #67c23a +} + +.el-tag--plain.el-tag--success.is-hit { + border-color: #67c23a +} + +.el-tag--plain.el-tag--success .el-tag__close { + color: #67c23a +} + +.el-tag--plain.el-tag--success .el-tag__close:hover { + color: #fff; + background-color: #67c23a +} + +.el-tag--plain.el-tag--warning { + background-color: #fff; + border-color: #f5dab1; + color: #e6a23c +} + +.el-tag--plain.el-tag--warning.is-hit { + border-color: #e6a23c +} + +.el-tag--plain.el-tag--warning .el-tag__close { + color: #e6a23c +} + +.el-tag--plain.el-tag--warning .el-tag__close:hover { + color: #fff; + background-color: #e6a23c +} + +.el-tag--plain.el-tag--danger { + background-color: #fff; + border-color: #fbc4c4; + color: #f56c6c +} + +.el-tag--plain.el-tag--danger.is-hit { + border-color: #f56c6c +} + +.el-tag--plain.el-tag--danger .el-tag__close { + color: #f56c6c +} + +.el-tag--plain.el-tag--danger .el-tag__close:hover { + color: #fff; + background-color: #f56c6c +} + +.el-tag--medium { + height: 28px; + line-height: 26px +} + +.el-tag--medium .el-icon-close { + transform: scale(.8) +} + +.el-tag--small { + height: 24px; + padding: 0 8px; + line-height: 22px +} + +.el-tag--small .el-icon-close { + transform: scale(.8) +} + +.el-tag--mini { + height: 20px; + padding: 0 5px; + line-height: 19px +} + +.el-tag--mini .el-icon-close { + margin-left: -3px; + transform: scale(.7) +} + +.el-checkbox { + color: #606266; + font-weight: 500; + font-size: 14px; + position: relative; + cursor: pointer; + display: inline-block; + white-space: nowrap; + user-select: none; + margin-right: 30px +} + +.el-checkbox.is-bordered { + padding: 9px 20px 9px 10px; + border-radius: 4px; + border: 1px solid #dcdfe6; + box-sizing: border-box; + line-height: normal; + height: 40px +} + +.el-checkbox.is-bordered.is-checked { + border-color: #409eff +} + +.el-checkbox.is-bordered.is-disabled { + border-color: #ebeef5; + cursor: not-allowed +} + +.el-checkbox.is-bordered + .el-checkbox.is-bordered { + margin-left: 10px +} + +.el-checkbox.is-bordered.el-checkbox--medium { + padding: 7px 20px 7px 10px; + border-radius: 4px; + height: 36px +} + +.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label { + line-height: 17px; + font-size: 14px +} + +.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner { + height: 14px; + width: 14px +} + +.el-checkbox.is-bordered.el-checkbox--small { + padding: 5px 15px 5px 10px; + border-radius: 3px; + height: 32px +} + +.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label { + line-height: 15px; + font-size: 12px +} + +.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner { + height: 12px; + width: 12px +} + +.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after { + height: 6px; + width: 2px +} + +.el-checkbox.is-bordered.el-checkbox--mini { + padding: 3px 15px 3px 10px; + border-radius: 3px; + height: 28px +} + +.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label { + line-height: 12px; + font-size: 12px +} + +.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner { + height: 12px; + width: 12px +} + +.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after { + height: 6px; + width: 2px +} + +.el-checkbox__input { + white-space: nowrap; + cursor: pointer; + outline: none; + display: inline-block; + line-height: 1; + position: relative; + vertical-align: middle +} + +.el-checkbox__input.is-disabled .el-checkbox__inner { + background-color: #edf2fc; + border-color: #dcdfe6; + cursor: not-allowed +} + +.el-checkbox__input.is-disabled .el-checkbox__inner:after { + cursor: not-allowed; + border-color: #c0c4cc +} + +.el-checkbox__input.is-disabled .el-checkbox__inner + .el-checkbox__label { + cursor: not-allowed +} + +.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner { + background-color: #f2f6fc; + border-color: #dcdfe6 +} + +.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after { + border-color: #c0c4cc +} + +.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner { + background-color: #f2f6fc; + border-color: #dcdfe6 +} + +.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before { + background-color: #c0c4cc; + border-color: #c0c4cc +} + +.el-checkbox__input.is-disabled + span.el-checkbox__label { + color: #c0c4cc; + cursor: not-allowed +} + +.el-checkbox__input.is-checked .el-checkbox__inner { + background-color: #409eff; + border-color: #409eff; +} + +.el-checkbox__input.is-checked .el-checkbox__inner:after { + transform: rotate(45deg) scaleY(1); +} + +.el-checkbox__input.is-checked + .el-checkbox__label { + color: #409eff +} + +.el-checkbox__input.is-focus .el-checkbox__inner { + border-color: #409eff +} + +.el-checkbox__input.is-indeterminate .el-checkbox__inner { + background-color: #409eff; + border-color: #409eff +} + +.el-checkbox__input.is-indeterminate .el-checkbox__inner:before { + content: ""; + position: absolute; + display: block; + background-color: #fff; + height: 2px; + transform: scale(.5); + left: 0; + right: 0; + top: 5px +} + +.el-checkbox__input.is-indeterminate .el-checkbox__inner:after { + display: none +} + +.el-checkbox__inner { + display: inline-block; + position: relative; + border: 1px solid #dcdfe6; + border-radius: 2px; + box-sizing: border-box; + width: 14px; + height: 14px; + background-color: #fff; + z-index: 1; + transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46); +} + +.el-checkbox__inner:hover { + border-color: #409eff +} + +.el-checkbox__inner:after { + box-sizing: content-box; + content: ""; + border: 1px solid #fff; + border-left: 0; + border-top: 0; + height: 7px; + left: 4px; + position: absolute; + top: 1px; + transform: rotate(45deg) scaleY(0); + width: 3px; + transition: transform .15s ease-in .05s; + transform-origin: center +} + +.el-checkbox__original { + opacity: 0; + outline: none; + position: absolute; + margin: 0; + width: 0; + height: 0; + z-index: -1 +} + +.el-checkbox__label { + display: inline-block; + padding-left: 10px; + line-height: 19px; + font-size: 14px +} + +.el-checkbox:last-of-type { + margin-right: 0 +} + +.el-checkbox-button, .el-checkbox-button__inner { + position: relative; + display: inline-block +} + +.el-checkbox-button__inner { + line-height: 1; + font-weight: 500; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + background: #fff; + border: 1px solid #dcdfe6; + border-left: 0; + color: #606266; + -webkit-appearance: none; + text-align: center; + box-sizing: border-box; + outline: none; + margin: 0; + transition: all .3s cubic-bezier(.645, .045, .355, 1); + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + padding: 12px 20px; + font-size: 14px; + border-radius: 0 +} + +.el-checkbox-button__inner.is-round { + padding: 12px 20px +} + +.el-checkbox-button__inner:hover { + color: #409eff +} + +.el-checkbox-button__inner [class*=el-icon-] { + line-height: .9 +} + +.el-checkbox-button__inner [class*=el-icon-] + span { + margin-left: 5px +} + +.el-checkbox-button__original { + opacity: 0; + outline: none; + position: absolute; + margin: 0; + z-index: -1 +} + +.el-checkbox-button.is-checked .el-checkbox-button__inner { + color: #fff; + background-color: #409eff; + border-color: #409eff; + box-shadow: -1px 0 0 0 #8cc5ff +} + +.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner { + border-left-color: #409eff +} + +.el-checkbox-button.is-disabled .el-checkbox-button__inner { + color: #c0c4cc; + cursor: not-allowed; + background-image: none; + background-color: #fff; + border-color: #ebeef5; + box-shadow: none +} + +.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner { + border-left-color: #ebeef5 +} + +.el-checkbox-button:first-child .el-checkbox-button__inner { + border-left: 1px solid #dcdfe6; + border-radius: 4px 0 0 4px; + box-shadow: none !important +} + +.el-checkbox-button.is-focus .el-checkbox-button__inner { + border-color: #409eff +} + +.el-checkbox-button:last-child .el-checkbox-button__inner { + border-radius: 0 4px 4px 0 +} + +.el-checkbox-button--medium .el-checkbox-button__inner { + padding: 10px 20px; + font-size: 14px; + border-radius: 0 +} + +.el-checkbox-button--medium .el-checkbox-button__inner.is-round { + padding: 10px 20px +} + +.el-checkbox-button--small .el-checkbox-button__inner { + padding: 9px 15px; + font-size: 12px; + border-radius: 0 +} + +.el-checkbox-button--small .el-checkbox-button__inner.is-round { + padding: 9px 15px +} + +.el-checkbox-button--mini .el-checkbox-button__inner { + padding: 7px 15px; + font-size: 12px; + border-radius: 0 +} + +.el-checkbox-button--mini .el-checkbox-button__inner.is-round { + padding: 7px 15px +} + +.el-checkbox-group { + font-size: 0 +} + +.el-radio { + color: #606266; + font-weight: 500; + line-height: 1; + position: relative; + cursor: pointer; + display: inline-block; + white-space: nowrap; + outline: none; + font-size: 14px; + margin-right: 30px; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none +} + +.el-radio.is-bordered { + padding: 12px 20px 0 10px; + border-radius: 4px; + border: 1px solid #dcdfe6; + box-sizing: border-box; + height: 40px +} + +.el-radio.is-bordered.is-checked { + border-color: #409eff +} + +.el-radio.is-bordered.is-disabled { + cursor: not-allowed; + border-color: #ebeef5 +} + +.el-radio.is-bordered + .el-radio.is-bordered { + margin-left: 10px +} + +.el-radio--medium.is-bordered { + padding: 10px 20px 0 10px; + border-radius: 4px; + height: 36px +} + +.el-radio--medium.is-bordered .el-radio__label { + font-size: 14px +} + +.el-radio--medium.is-bordered .el-radio__inner { + height: 14px; + width: 14px +} + +.el-radio--small.is-bordered { + padding: 8px 15px 0 10px; + border-radius: 3px; + height: 32px +} + +.el-radio--small.is-bordered .el-radio__label { + font-size: 12px +} + +.el-radio--small.is-bordered .el-radio__inner { + height: 12px; + width: 12px +} + +.el-radio--mini.is-bordered { + padding: 6px 15px 0 10px; + border-radius: 3px; + height: 28px +} + +.el-radio--mini.is-bordered .el-radio__label { + font-size: 12px +} + +.el-radio--mini.is-bordered .el-radio__inner { + height: 12px; + width: 12px +} + +.el-radio:last-child { + margin-right: 0 +} + +.el-radio__input { + white-space: nowrap; + cursor: pointer; + outline: none; + display: inline-block; + line-height: 1; + position: relative; + vertical-align: middle +} + +.el-radio__input.is-disabled .el-radio__inner { + background-color: #f5f7fa; + border-color: #e4e7ed; + cursor: not-allowed +} + +.el-radio__input.is-disabled .el-radio__inner:after { + cursor: not-allowed; + background-color: #f5f7fa +} + +.el-radio__input.is-disabled .el-radio__inner + .el-radio__label { + cursor: not-allowed +} + +.el-radio__input.is-disabled.is-checked .el-radio__inner { + background-color: #f5f7fa; + border-color: #e4e7ed +} + +.el-radio__input.is-disabled.is-checked .el-radio__inner:after { + background-color: #c0c4cc +} + +.el-radio__input.is-disabled + span.el-radio__label { + color: #c0c4cc; + cursor: not-allowed +} + +.el-radio__input.is-checked .el-radio__inner { + border-color: #409eff; + background: #409eff +} + +.el-radio__input.is-checked .el-radio__inner:after { + transform: translate(-50%, -50%) scale(1) +} + +.el-radio__input.is-checked + .el-radio__label { + color: #409eff +} + +.el-radio__input.is-focus .el-radio__inner { + border-color: #409eff +} + +.el-radio__inner { + border: 1px solid #dcdfe6; + border-radius: 100%; + width: 14px; + height: 14px; + background-color: #fff; + position: relative; + cursor: pointer; + display: inline-block; + box-sizing: border-box +} + +.el-radio__inner:hover { + border-color: #409eff +} + +.el-radio__inner:after { + width: 4px; + height: 4px; + border-radius: 100%; + background-color: #fff; + content: ""; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%) scale(0); + transition: transform .15s ease-in +} + +.el-radio__original { + opacity: 0; + outline: none; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: 0 +} + +.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner { + /*box-shadow: 0 0 2px 2px #409eff*/ +} + +/*滚动条*/ +.el-scrollbar { + overflow: hidden; + position: relative +} + +.el-scrollbar:active > .el-scrollbar__bar, .el-scrollbar:focus > .el-scrollbar__bar, .el-scrollbar:hover > .el-scrollbar__bar { + opacity: 1; + transition: opacity .34s ease-out +} + +.el-scrollbar__wrap { + overflow: scroll; + height: 100% +} + +.el-scrollbar__wrap--hidden-default { + scrollbar-width: none +} + +.el-scrollbar__wrap--hidden-default::-webkit-scrollbar { + width: 0; + height: 0 +} + +.el-scrollbar__thumb { + position: relative; + display: block; + width: 0; + height: 0; + cursor: pointer; + border-radius: inherit; + background-color: rgba(144, 147, 153, .3); + transition: background-color .3s +} + +.el-scrollbar__thumb:hover { + background-color: rgba(144, 147, 153, .5) +} + +.el-scrollbar__bar { + position: absolute; + right: 2px; + bottom: 2px; + z-index: 1; + border-radius: 4px; + opacity: 0; + transition: opacity .12s ease-out +} + +.el-scrollbar__bar.is-vertical { + width: 6px; + top: 2px +} + +.el-scrollbar__bar.is-vertical > div { + width: 100% +} + +.el-scrollbar__bar.is-horizontal { + height: 6px; + left: 2px +} + +.el-scrollbar__bar.is-horizontal > div { + height: 100% +} + +.el-cascader { + display: inline-block; + position: relative; + font-size: 14px; + line-height: 40px +} + +.el-cascader:not(.is-disabled):hover .el-input__inner { + cursor: pointer; + border-color: #c0c4cc +} + +.el-cascader .el-input { + cursor: pointer +} + +.el-cascader .el-input .el-input__inner { + text-overflow: ellipsis +} + +.el-cascader .el-input .el-input__inner:focus { + border-color: #409eff +} + +.el-cascader .el-input .el-icon-arrow-down { + display: inline-block; + transition: transform .3s; + font-size: 14px +} + +.el-cascader .el-input .el-icon-arrow-down.is-reverse { + transform: rotate(180deg) +} + +.el-cascader .el-input .el-icon-circle-close:hover { + color: #909399 +} + +.el-cascader .el-input.is-focus .el-input__inner { + border-color: #409eff +} + +.el-cascader--medium { + font-size: 14px; + line-height: 36px +} + +.el-cascader--small { + font-size: 13px; + line-height: 32px +} + +.el-cascader--mini { + font-size: 12px; + line-height: 28px +} + +.el-cascader.is-disabled .el-cascader__label { + z-index: 2; + color: #c0c4cc +} + +.el-cascader__dropdown { + margin: 5px 0; + font-size: 14px; + background: #fff; + border: 1px solid #e4e7ed; + border-radius: 4px; + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1) +} + +.el-cascader__tags { + position: absolute; + left: 0; + right: 30px; + top: 50%; + transform: translateY(-50%); + display: flex; + flex-wrap: wrap; + line-height: normal; + text-align: left; + box-sizing: border-box +} + +.el-cascader__tags .el-tag { + display: inline-flex; + align-items: center; + max-width: 100%; + margin: 2px 0 2px 6px; + text-overflow: ellipsis; + background: #f0f2f5 +} + +.el-cascader__tags .el-tag:not(.is-hit) { + border-color: transparent +} + +.el-cascader__tags .el-tag > span { + flex: 1; + overflow: hidden; + text-overflow: ellipsis +} + +.el-cascader__tags .el-tag .el-icon-close { + flex: none; + background-color: #c0c4cc; + color: #fff +} + +.el-cascader__tags .el-tag .el-icon-close:hover { + background-color: #909399 +} + +.el-cascader__suggestion-panel { + border-radius: 4px +} + +.el-cascader__suggestion-list { + max-height: 204px; + margin: 0; + padding: 6px 0; + font-size: 14px; + color: #606266; + text-align: center +} + +.el-cascader__suggestion-item { + display: flex; + justify-content: space-between; + align-items: center; + height: 34px; + padding: 0 15px; + text-align: left; + outline: none; + cursor: pointer +} + +.el-cascader__suggestion-item:focus, .el-cascader__suggestion-item:hover { + background: #f5f7fa +} + +.el-cascader__suggestion-item.is-checked { + color: #409eff; + font-weight: 700 +} + +.el-cascader__suggestion-item .el-icon-check { + margin-right: 15px; +} + +.el-cascader__suggestion-item > span { + margin-right: 10px +} + +.el-cascader__empty-text { + margin: 10px 0; + color: #c0c4cc +} + +.el-cascader__search-input { + flex: 1; + height: 24px; + min-width: 60px; + margin: 2px 0 2px 15px; + padding: 0; + color: #606266; + border: none; + outline: none; + box-sizing: border-box +} + +.el-cascader__search-input::placeholder { + color: #c0c4cc +} + +/*cascader面板*/ +.el-cascader-panel { + display: flex; + border-radius: 4px; + font-size: 14px +} + +.el-cascader-panel.is-bordered { + border: 1px solid #e4e7ed; + border-radius: 4px +} + +.el-cascader-menu { + min-width: 180px; + box-sizing: border-box; + color: #606266; + border-right: 1px solid #e4e7ed +} + +.el-cascader-menu:last-child { + border-right: none +} + +.el-cascader-menu:last-child .el-cascader-node { + padding-right: 26px +} + +.el-cascader-menu__wrap { + height: 204px +} + +.el-cascader-menu__list { + position: relative; + min-height: 100%; + padding: 6px 0; + list-style: none; + box-sizing: border-box; +} + +.el-cascader-menu__hover-zone { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none +} + +.el-cascader-menu__empty-text { + position: absolute; + top: 50%; + left: 46%; + transform: translate(-50%, -50%); + text-align: center; + color: #c0c4cc +} + +.el-cascader-node { + position: relative; + display: flex; + align-items: center; + padding: 0 25px 0 15px; + height: 34px; + line-height: 34px; + outline: none +} + +.el-cascader-node.is-selectable.in-active-path { + color: #606266 +} + +.el-cascader-node.in-active-path, .el-cascader-node.is-active, .el-cascader-node.is-selectable.in-checked-path { + color: #409eff; + font-weight: 700 +} + +.el-cascader-node:not(.is-disabled) { + cursor: pointer +} + +.el-cascader-node:not(.is-disabled):focus, .el-cascader-node:not(.is-disabled):hover { + background: #f5f7fa +} + +.el-cascader-node.is-disabled { + color: #c0c4cc; + cursor: not-allowed +} + +.el-cascader-node__prefix { + position: absolute; + left: 10px +} + +.el-cascader-node__postfix { + position: absolute; + right: 10px +} + +.el-cascader-node__label { + flex: 1; + padding: 0 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis +} + +.el-cascader-node > .el-radio { + margin-right: 0 +} + +.el-cascader-node > .el-radio .el-radio__label { + padding-left: 0 +} + +/*输入框*/ +.el-input { + position: relative; + font-size: 14px; + display: inline-block; + width: 100% +} + +.el-input::-webkit-scrollbar { + z-index: 11; + width: 6px +} + +.el-input::-webkit-scrollbar:horizontal { + height: 6px +} + +.el-input::-webkit-scrollbar-thumb { + border-radius: 5px; + width: 6px; + background: #b4bccc +} + +.el-input::-webkit-scrollbar-corner, .el-input::-webkit-scrollbar-track { + background: #fff +} + +.el-input::-webkit-scrollbar-track-piece { + background: #fff; + width: 6px +} + +.el-input .el-input__clear { + color: #c0c4cc; + font-size: 14px; + cursor: pointer; + transition: color .2s cubic-bezier(.645, .045, .355, 1) +} + +.el-input .el-input__clear:hover { + color: #909399 +} + +.el-input .el-input__count { + height: 100%; + display: inline-flex; + align-items: center; + color: #909399; + font-size: 12px +} + +.el-input .el-input__count .el-input__count-inner { + background: #fff; + line-height: normal; + display: inline-block; + padding: 0 5px +} + +.el-input__inner { + -webkit-appearance: none; + background-color: #fff; + background-image: none; + border-radius: 4px; + border: 1px solid #dcdfe6; + box-sizing: border-box; + color: #606266; + display: inline-block; + font-size: inherit; + height: 40px; + line-height: 40px; + outline: none; + padding: 0 15px; + transition: border-color .2s cubic-bezier(.645, .045, .355, 1); + width: 100% +} + +.el-input__inner::-ms-reveal { + display: none +} + +.el-input__inner::placeholder { + color: #c0c4cc +} + +.el-input__inner:hover { + border-color: #c0c4cc +} + +.el-input__inner:focus { + outline: none; + border-color: #409eff +} + +.el-input__suffix { + position: absolute; + height: 100%; + right: 5px; + top: 0; + text-align: center; + color: #c0c4cc; + transition: all .3s; + pointer-events: none; + display: flex; + flex-direction: column; + justify-content: center; +} + +.el-input__suffix-inner { + pointer-events: all +} + +.el-input__prefix { + position: absolute; + left: 5px; + top: 0; + color: #c0c4cc +} + +.el-input__icon, .el-input__prefix { + height: 100%; + text-align: center; + transition: all .3s +} + +.el-input__icon { + width: 25px; + line-height: 40px +} + +.el-input__icon:after { + content: ""; + height: 100%; + width: 0; + display: inline-block; + vertical-align: middle +} + +.el-input__validateIcon { + pointer-events: none +} + +.el-input.is-active .el-input__inner { + outline: none; + border-color: #409eff +} + +.el-input.is-disabled .el-input__inner { + background-color: #f5f7fa; + border-color: #e4e7ed; + color: #c0c4cc; + cursor: not-allowed +} + +.el-input.is-disabled .el-input__inner::placeholder { + color: #c0c4cc +} + +.el-input.is-disabled .el-input__icon { + cursor: not-allowed +} + +.el-input.is-exceed .el-input__inner { + border-color: #f56c6c +} + +.el-input.is-exceed .el-input__suffix .el-input__count { + color: #f56c6c +} + +.el-input--suffix .el-input__inner { + padding-right: 30px +} + +.el-input--prefix .el-input__inner { + padding-left: 30px +} + +.el-input--medium { + font-size: 14px +} + +.el-input--medium .el-input__inner { + height: 36px; + line-height: 36px +} + +.el-input--medium .el-input__icon { + line-height: 36px +} + +.el-input--small { + font-size: 13px +} + +.el-input--small .el-input__inner { + height: 32px; + line-height: 32px +} + +.el-input--small .el-input__icon { + line-height: 32px +} + +.el-input--mini { + font-size: 12px +} + +.el-input--mini .el-input__inner { + height: 28px; + line-height: 28px +} + +.el-input--mini .el-input__icon { + line-height: 28px +} + +.el-input-group { + line-height: normal; + display: inline-table; + width: 100%; + border-collapse: separate; + border-spacing: 0 +} + +.el-input-group > .el-input__inner { + vertical-align: middle; + display: table-cell +} + +.el-input-group__append, .el-input-group__prepend { + background-color: #f5f7fa; + color: #909399; + vertical-align: middle; + display: table-cell; + position: relative; + border: 1px solid #dcdfe6; + border-radius: 4px; + padding: 0 20px; + width: 1px; + white-space: nowrap +} + +.el-input-group__append:focus, .el-input-group__prepend:focus { + outline: none +} + +.el-input-group__append .el-button, .el-input-group__append .el-select, .el-input-group__prepend .el-button, .el-input-group__prepend .el-select { + display: inline-block; + margin: -10px -20px +} + +.el-input-group__append button.el-button, .el-input-group__append div.el-select .el-input__inner, .el-input-group__append div.el-select:hover .el-input__inner, .el-input-group__prepend button.el-button, .el-input-group__prepend div.el-select .el-input__inner, .el-input-group__prepend div.el-select:hover .el-input__inner { + border-color: transparent; + background-color: transparent; + color: inherit; + border-top: 0; + border-bottom: 0 +} + +.el-input-group__append .el-button, .el-input-group__append .el-input, .el-input-group__prepend .el-button, .el-input-group__prepend .el-input { + font-size: inherit +} + +.el-input-group__prepend { + border-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.el-input-group__append { + border-left: 0 +} + +.el-input-group--prepend .el-input__inner, .el-input-group__append { + border-top-left-radius: 0; + border-bottom-left-radius: 0 +} + +.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner { + border-color: transparent +} + +.el-input-group--append .el-input__inner { + border-top-right-radius: 0; + border-bottom-right-radius: 0 +} + +.el-input-group--append .el-select .el-input.is-focus .el-input__inner { + border-color: transparent +} + +.el-input__inner::-ms-clear { + display: none; + width: 0; + height: 0 +} + +::-webkit-scrollbar { + width: 0; +} diff --git a/public/static/plugs/layui_exts/cascader.js b/public/static/plugs/layui_exts/cascader.js new file mode 100644 index 000000000..229b233af --- /dev/null +++ b/public/static/plugs/layui_exts/cascader.js @@ -0,0 +1,2085 @@ +/** + * 仿element-ui,级联选择器 + * 已实现单选、多选、无关联选择 + * 其他功能:组件禁用、节点禁用、自定义属性、自定义空面板提示,自定义无选择时的提示、多选标签折叠、回显、搜索、动态加载、最大选中数量限制、禁用项固定等操作。 + * element-ui没有的功能:最大选中数量限制、禁用项固定 + * author: yixiaco + * gitee: https://gitee.com/yixiacoco/lay_cascader + * github: https://github.com/yixiaco/lay_cascader + */ +layui.define(["jquery"], function (exports) { + var $ = layui.jquery; + + /** + * 级联各项节点对象 + * @param data 原始对象信息 + * @param cascader 级联对象 + * @param level 层级,从0开始 + * @param parentNode 父节点对象 + * @constructor + */ + function Node(data, cascader, level, parentNode) { + this.data = data; + this.cascader = cascader; + this.config = cascader.config; + this.props = cascader.props; + this.level = level; + this.parentNode = parentNode; + // 引入的icon图标 + this.icons = cascader.icons; + //该节点是否被选中 0:未选中,1:选中,2:不定 + this._checked = 0; + // 是否正在加载中 + this._loading = false; + // 每个Node的唯一标识 + this.nodeId = cascader.data.nodeId++; + } + + Node.prototype = { + constructor: Node, + /** 最顶级父节点 */ + get topParentNode() { + return !this.parentNode && this || this.topParentNode; + }, + /** 子节点 */ + childrenNode: undefined, + get loading() { + return this._loading; + }, + set loading(loading) { + var $li = this.$li; + if ($li) { + var rightIcon = this.icons.right; + var loadingIcon = this.icons.loading; + var $i = $li.find('i'); + if (loading) { + $i.addClass(loadingIcon); + $i.removeClass(rightIcon); + } else { + $i.addClass(rightIcon); + $i.removeClass(loadingIcon); + } + } + return this._loading = loading; + }, + /** 当前节点的显示文本 */ + get label() { + return this.data[this.props.label]; + }, + /** 当前节点的值 */ + get value() { + return this.data[this.props.value]; + }, + /** 是否禁用 */ + get disabled() { + var multiple = this.props.multiple; + var maxSize = this.config.maxSize; + var checkedNodeIds = this.cascader.data.checkedNodeIds; + var disabledName = this.props.disabled; + var checkStrictly = this.props.checkStrictly; + // 检查是否超过最大值限制 + if (multiple && maxSize !== 0) { + if (checkedNodeIds.length >= maxSize && checkedNodeIds.indexOf(this.nodeId) === -1) { + // 如果是关联的多选,需要查询叶子节点是否有被选中的项 + if (!checkStrictly) { + var leafChildren = this.getAllLeafChildren(); + var nodeIds = leafChildren.map(function (value) { + return value.nodeId + }); + // 如果叶子节点不包含,则直接返回true + if (!nodeIds.some(function (nodeId) { + return checkedNodeIds.indexOf(nodeId) !== -1; + })) { + return true; + } + } else { + return true; + } + } + } + if (!checkStrictly) { + var path = this.path; + return path.some(function (node) { + return node.data[disabledName]; + }); + } else { + return this.data[disabledName]; + } + }, + /** 子节点数据 */ + get children() { + return this.data[this.props.children]; + }, + set children(children) { + this.data[this.props.children] = children; + }, + /** 叶子节点 */ + get leaf() { + var leaf = this.data[this.props.leaf]; + if (typeof leaf === 'boolean') { + return leaf; + } + // 如果children不为空,则判断是否是子节点 + if (this.children) { + return this.children.length <= 0; + } + return true; + }, + /** 当前单选值 */ + get activeNodeId() { + return this.cascader.data.activeNodeId; + }, + /** 当前复选框值 */ + get checkedNodeIds() { + return this.cascader.data.checkedNodeIds; + }, + /** 路径 */ + get path() { + var parentNode = this.parentNode; + if (parentNode) { + return parentNode.path.concat([this]); + } else { + return [this]; + } + }, + /** 是否正在搜索中 */ + get isFiltering() { + return this.cascader.isFiltering; + }, + /** 输入框的tag标签 */ + get $tag() { + var cascader = this.cascader; + var showAllLevels = this.config.showAllLevels; + var disabled = this.config.disabled; + var nodeDisabled = this.disabled; + var disabledFixed = this.config.disabledFixed; + + var label = this.getPathLabel(showAllLevels); + var $tag = cascader.get$tag(label, !disabled && (!nodeDisabled || !disabledFixed)); + var self = this; + $tag.find('i').click(function (event) { + event.stopPropagation(); + self.selectedValue(); + cascader.removeTag(self.value, self); + }); + return $tag; + }, + /** + * 完整路径的标签 + * @param showAllLevels + * @returns {string} + */ + getPathLabel: function (showAllLevels) { + var path = this.path; + var separator = this.config.separator; + + var label; + if (showAllLevels) { + label = path.map(function (node) { + return node.label; + }).join(separator); + } else { + label = path[path.length - 1].label; + } + return label; + }, + /** + * 初始化 + */ + init: function () { + var multiple = this.props.multiple; + var checkStrictly = this.props.checkStrictly; + var fromIcon = this.icons.from; + var rightIcon = this.icons.right; + var icon = ''; + var label = this.label; + if (!this.leaf) { + icon = rightIcon; + } + this.$li = $(''); + + // 节点渲染 + if (!multiple && !checkStrictly) { + this._renderRadio(); + } else if (!multiple && checkStrictly) { + this._renderRadioCheckStrictly(); + } else if (multiple && !checkStrictly) { + this._renderMultiple(); + } else if (multiple && checkStrictly) { + this._renderMultipleCheckStrictly(); + } + }, + /** + * 初始化可搜索li + */ + initSuggestionLi: function () { + var label = this.getPathLabel(true); + this.$suggestionLi = $('
  • ' + label + '
  • '); + // 节点渲染 + this._renderFiltering(); + }, + /** + * 绑定到菜单中 + * @param $list li节点 + */ + bind: function ($list) { + this.init(); + $list.append(this.$li); + }, + /** + * 绑定可搜索到列表中 + * @param $list + */ + bindSuggestion: function ($list) { + this.initSuggestionLi(); + $list.append(this.$suggestionLi); + }, + /** + * 可搜索渲染 + * @private + */ + _renderFiltering: function () { + var $li = this.$suggestionLi; + var nodeId = this.nodeId; + var fromIcon = this.icons.from; + var okIcon = this.icons.ok; + var self = this; + var cascader = this.cascader; + var multiple = this.props.multiple; + + var icon = ''; + $li.click(function (event) { + event.stopPropagation(); + self.selectedValue(); + if (multiple) { + if (self.checkedNodeIds.indexOf(nodeId) === -1) { + $li.removeClass('is-checked'); + $li.find('.el-icon-check').remove(); + } else { + $li.addClass('is-checked'); + $li.append(icon); + } + } else { + // 关闭面板 + cascader.close(); + } + }); + + if (multiple && self.checkedNodeIds.indexOf(nodeId) !== -1 + || !multiple && self.activeNodeId === nodeId) { + $li.addClass('is-checked'); + $li.append(icon) + } + }, + /** + * 单选&&关联 + * @private + */ + _renderRadio: function () { + var $li = this.$li; + var nodeId = this.nodeId; + var fromIcon = this.icons.from; + var okIcon = this.icons.ok; + var level = this.level; + var leaf = this.leaf; + var self = this; + var cascader = this.cascader; + var activeNode = this.cascader.data.activeNode; + var parentNode = this.parentNode; + + if (self.activeNodeId && activeNode.path.some(function (node) { + return node.nodeId === nodeId; + })) { + if (self.activeNodeId === nodeId) { + $li.prepend(''); + } + $li.addClass('is-active'); + $li.addClass('in-checked-path'); + } + + // 是否禁用 + if (this.disabled) { + $li.addClass('is-disabled'); + return; + } + + $li.addClass('is-selectable'); + + if (parentNode) { + parentNode.$li.siblings().removeClass('in-active-path'); + parentNode.$li.addClass('in-active-path'); + } + + // 触发下一个节点 + this._liClick(function (event) { + event.stopPropagation(); + var childrenNode = self.childrenNode; + if (leaf && event.type === 'click') { + self.selectedValue(); + // 关闭面板 + cascader.close(); + } + // 添加下级菜单 + cascader._appendMenu(childrenNode, level + 1, self); + }); + }, + /** + * 单选&&非关联 + * @private + */ + _renderRadioCheckStrictly: function () { + var $li = this.$li; + var nodeId = this.nodeId; + var level = this.level; + var leaf = this.leaf; + var self = this; + var cascader = this.cascader; + var activeNode = cascader.data.activeNode; + var parentNode = this.parentNode; + + $li.addClass('is-selectable'); + // 任意一级单选 + var $radio = $(''); + this.$radio = $radio; + $li.prepend($radio); + if (parentNode) { + parentNode.$li.siblings().removeClass('in-active-path'); + parentNode.$li.addClass('in-active-path'); + } + + // 触发下一个节点 + this._liClick(function (event) { + event.stopPropagation(); + var childrenNode = self.childrenNode; + if (!self.disabled && leaf && event.type === 'click') { + self.selectedValue(); + } + // 添加下级菜单 + cascader._appendMenu(childrenNode, level + 1, self); + }); + + if (self.activeNodeId && activeNode.path.some(function (node) { + return node.nodeId === nodeId; + })) { + if (self.activeNodeId === nodeId) { + $radio.find('.el-radio__input').addClass('is-checked'); + } + $li.addClass('is-active'); + $li.addClass('in-checked-path'); + } + + if (this.disabled) { + $radio.addClass('is-disabled'); + $radio.find('.el-radio__input').addClass('is-disabled'); + return; + } + // 选中事件 + $radio.click(function (event) { + event.preventDefault(); + !leaf && self.selectedValue(); + }); + }, + /** + * 多选&&关联 + * @private + */ + _renderMultiple: function () { + var $li = this.$li; + var level = this.level; + var leaf = this.leaf; + var self = this; + var cascader = this.cascader; + var checked = this._checked; + var parentNode = this.parentNode; + + $li.addClass('el-cascader-node'); + + // 多选框 + var $checked = $(''); + this.$checked = $checked; + $li.prepend($checked); + + // 渲染 + if (checked === 1) { + this.$checked.find('.el-checkbox__input').addClass('is-checked'); + } else if (checked === 2) { + this.$checked.find('.el-checkbox__input').addClass('is-indeterminate'); + } + + if (parentNode) { + parentNode.$li.siblings().removeClass('in-active-path'); + parentNode.$li.addClass('in-active-path'); + } + + // 触发下一个节点 + this._liClick(function (event) { + event.stopPropagation(); + var childrenNode = self.childrenNode; + if (!self.disabled && leaf && event.type === 'click') { + // 最后一级就默认选择 + self.selectedValue(); + } + // 添加下级菜单 + cascader._appendMenu(childrenNode, level + 1, self); + }); + + if (this.disabled) { + $li.addClass('is-disabled'); + $checked.addClass('is-disabled'); + $checked.find('.el-checkbox__input').addClass('is-disabled'); + return; + } + + // 选中事件 + $checked.click(function (event) { + event.preventDefault(); + if (!leaf) { + var childrenNode = self.childrenNode; + self.selectedValue(); + cascader._appendMenu(childrenNode, level + 1, self); + } + }); + }, + /** + * 多选&&非关联 + * @private + */ + _renderMultipleCheckStrictly: function () { + var $li = this.$li; + var level = this.level; + var leaf = this.leaf; + var self = this; + var cascader = this.cascader; + var checkedNodeIds = cascader.data.checkedNodeIds; + var checkedNodes = cascader.data.checkedNodes; + var nodeId = this.nodeId; + var parentNode = this.parentNode; + + $li.addClass('el-cascader-node is-selectable'); + + // 多选框 + var $checked = $(''); + this.$checked = $checked; + $li.prepend($checked); + + // 渲染 + var exist = checkedNodes.some(function (node) { + return node.path.some(function (node) { + return node.nodeId === nodeId; + }) + }); + if (exist) { + $li.addClass('in-checked-path'); + if (checkedNodeIds.indexOf(nodeId) !== -1) { + this.$checked.find('.el-checkbox__input').addClass('is-checked'); + } + } + + if (parentNode) { + parentNode.$li.siblings().removeClass('in-active-path'); + parentNode.$li.addClass('in-active-path'); + } + + // 触发下一个节点 + this._liClick(function (event) { + event.stopPropagation(); + var childrenNode = self.childrenNode; + if (!self.disabled && leaf && event.type === 'click') { + // 最后一级就默认选择 + self.selectedValue(); + } + // 添加下级菜单 + cascader._appendMenu(childrenNode, level + 1, self); + }); + + if (this.disabled) { + $checked.addClass('is-disabled'); + $checked.find('.el-checkbox__input').addClass('is-disabled'); + return; + } + // 选中事件 + $checked.click(function (event) { + event.preventDefault(); + if (!leaf) { + self.selectedValue(); + var childrenNode = self.childrenNode; + // 添加下级菜单 + cascader._appendMenu(childrenNode, level + 1, self); + } + }); + }, + /** + * 向上传递 + * @param callback 执行方法,如果返回false,则中断执行 + * @param advance 是否先执行一次 + * @param self 自身 + */ + transferParent: function (callback, advance, self) { + if (!self) { + self = this; + } + if (this !== self || advance) { + var goOn = callback && callback(this); + if (goOn === false) { + return; + } + } + this.parentNode && this.parentNode.transferParent(callback, advance, self); + }, + /** + * 向下传递 + * @param callback 执行的方法,如果返回false,则中断执行 + * @param advance 是否先执行一次 + * @param self 自身 + */ + transferChildren: function (callback, advance, self) { + if (!self) { + self = this; + } + if (this !== self || advance) { + var goOn = callback && callback(this); + if (goOn === false) { + return; + } + } + var children = this.getChildren(); + if (children && children.length > 0) { + for (var index in children) { + children[index].transferChildren(callback, advance, self); + } + } + }, + /** + * 设置级联值 + */ + selectedValue: function () { + var nodeId = this.nodeId; + var cascader = this.cascader; + var multiple = this.props.multiple; + var checkStrictly = this.props.checkStrictly; + var leaf = this.leaf; + if (!multiple && (leaf || checkStrictly)) { + cascader._setActiveValue(nodeId, this); + } else if (multiple) { + var checkedNodeIds = cascader.data.checkedNodeIds; + var checkedNodes = cascader.data.checkedNodes; + var disabledFixed = this.config.disabledFixed; + var paths; + if (checkStrictly) { + var index = checkedNodeIds.indexOf(nodeId); + if (index === -1) { + paths = checkedNodes.concat([this]); + } else { + paths = checkedNodes.concat(); + paths.splice(index, 1); + } + } else { + var allLeafChildren = this.getAllLeafChildren(); + var checked; + if (this._checked !== 1 && disabledFixed) { + checked = this._getMultipleChecked(allLeafChildren); + } else { + checked = this._checked; + } + if (checked === 1) { + // 选中->未选中 + paths = checkedNodes.filter(function (node1) { + return !allLeafChildren.some(function (node2) { + return node1.nodeId === node2.nodeId; + }); + }); + } else { + // 未选中、部分选中->选中 + var add = allLeafChildren.filter(function (node) { + return checkedNodeIds.indexOf(node.nodeId) === -1; + }); + paths = checkedNodes.concat(add); + } + } + var nodeIds = paths.map(function (node) { + return node.nodeId; + }); + cascader._setCheckedValue(nodeIds, paths); + } + }, + _liLoad: function (event, callback) { + var leaf = this.leaf; + var lazy = this.props.lazy; + var lazyLoad = this.props.lazyLoad; + var children = this.children; + var self = this; + var cascader = this.cascader; + var level = this.level; + var multiple = this.props.multiple; + var checkStrictly = this.props.checkStrictly; + if (!leaf && (!children || children.length === 0) && lazy) { + if (!self.loading) { + self.loading = true; + lazyLoad(self, function (nodes) { + self.loading = false; + self.setChildren(cascader.initNodes(nodes, level + 1, self)); + self.children = nodes; + callback && callback(event); + // 多选&关联时,重新同步下父级节点的样式 + multiple && !checkStrictly && self.transferParent(function (node) { + node.syncStyle(); + }, true); + }); + } + } else { + callback && callback(event); + } + }, + /** + * 点击li事件 + * @param callback + * @private + */ + _liClick: function (callback) { + var leaf = this.leaf; + var $li = this.$li; + var self = this; + + function load(event) { + self._liLoad(event, callback); + } + + if (this.props.expandTrigger === "click" || leaf) { + $li.click(load); + } + if (this.props.expandTrigger === "hover") { + $li.mouseenter(load); + } + }, + setChildren: function (children) { + this.childrenNode = children; + }, + getChildren: function () { + return this.childrenNode; + }, + /** + * 同步样式 + */ + syncStyle: function () { + var multiple = this.props.multiple; + var checkStrictly = this.props.checkStrictly; + if (multiple) { + //多选 + if (checkStrictly) { + this._sync.syncMultipleCheckStrictly(this); + } else { + this._sync.syncMultiple(this); + } + } else { + //单选 + if (checkStrictly) { + this._sync.syncRadioCheckStrictly(this); + } else { + this._sync.syncRadio(this); + } + } + }, + /** + * 同步本节点样式 + */ + _sync: { + /** + * 同步单选关联样式 + */ + syncRadio: function (self) { + var $li = self.$li; + var fromIcon = self.icons.from; + var okIcon = self.icons.ok; + var multiple = self.props.multiple; + var checkStrictly = self.props.checkStrictly; + var nodeId = self.nodeId; + if (!$li || multiple || checkStrictly) { + return; + } + var activeNode = self.cascader.data.activeNode; + if (self.activeNodeId === nodeId) { + var ok = $li.find('.' + okIcon); + if (ok.length === 0) { + $li.prepend(''); + } + } else { + $li.find('.' + okIcon).remove(); + } + if (activeNode && activeNode.path.some(function (node) { + return node.nodeId === nodeId; + })) { + $li.addClass('is-active'); + $li.addClass('in-checked-path'); + } else { + $li.removeClass('is-active'); + $li.removeClass('in-checked-path'); + } + }, + /** + * 同步单选非关联样式 + */ + syncRadioCheckStrictly: function (self) { + var $li = self.$li; + var checkStrictly = self.props.checkStrictly; + var multiple = self.props.multiple; + if (!$li || multiple || !checkStrictly) { + return; + } + var $radio = self.$radio; + var activeNode = self.cascader.data.activeNode; + var nodeId = self.nodeId; + if (self.activeNodeId === nodeId) { + $radio.find('.el-radio__input').addClass('is-checked'); + } else { + $radio.find('.el-radio__input').removeClass('is-checked'); + } + if (activeNode && activeNode.path.some(function (node) { + return node.nodeId === nodeId; + })) { + $li.addClass('is-active'); + $li.addClass('in-checked-path'); + } else { + $li.removeClass('is-active'); + $li.removeClass('in-checked-path'); + } + }, + /** + * 同步多选关联样式 + */ + syncMultiple: function (self) { + var $li = self.$li; + var checkStrictly = self.props.checkStrictly; + var multiple = self.props.multiple; + var disabledFixed = self.config.disabledFixed; + if (!multiple || checkStrictly) { + return; + } + var allLeafChildren = self.getAllLeafChildren(disabledFixed); + // 全部未选中 0 + // 全部选中 1 + // 部分选中 2 + var checked = self._getMultipleChecked(allLeafChildren); + self._checked = checked; + if (!$li) { + return; + } + var $checkbox = self.$checked.find('.el-checkbox__input'); + if (checked === 0) { + $checkbox.removeClass('is-checked'); + $checkbox.removeClass('is-indeterminate'); + } else if (checked === 1) { + $checkbox.removeClass('is-indeterminate'); + $checkbox.addClass('is-checked'); + } else if (checked === 2) { + $checkbox.removeClass('is-checked'); + $checkbox.addClass('is-indeterminate'); + } + }, + /** + * 同步多选非关联样式 + */ + syncMultipleCheckStrictly: function (self) { + var $li = self.$li; + var checkStrictly = self.props.checkStrictly; + var multiple = self.props.multiple; + if (!$li || !multiple || !checkStrictly) { + return; + } + var checkedNodes = self.cascader.data.checkedNodes; + var checkedNodeIds = self.checkedNodeIds; + var nodeId = self.nodeId; + var exist = checkedNodes.some(function (node) { + return node.path.some(function (node) { + return node.nodeId === nodeId; + }); + }); + var $checkbox = self.$checked.find('.el-checkbox__input'); + if (checkedNodeIds.some(function (checkedNodeId) { + return checkedNodeId === nodeId; + })) { + // 选中 + $checkbox.addClass('is-checked'); + } else { + // 未选中 + $checkbox.removeClass('is-checked'); + } + if (exist) { + $li.addClass('in-checked-path'); + } else { + $li.removeClass('in-checked-path'); + } + } + }, + /** + * 获取叶子节点value值 + * @param disabled 是否包含禁用,默认不包含 + * @returns {Node[]|*[]} + */ + getAllLeafChildren: function (disabled) { + var leaf = this.leaf; + if (leaf) { + return [this]; + } else { + var leafs = []; + this.transferChildren(function (node) { + if (node.disabled && !disabled) { + return false; + } + node.leaf && leafs.push(node); + }); + return leafs; + } + }, + /** + * 展开当前节点 + */ + expandPanel: function () { + var path = this.path; + var cascader = this.cascader; + path.forEach(function (node, index, array) { + if (index !== array.length - 1) { + var childrenNode = node.childrenNode; + cascader._appendMenu(childrenNode, node.level + 1, node.parentNode); + } + }); + }, + _getMultipleChecked: function (leafNodes) { + var cascader = this.cascader; + var checkedNodeIds = cascader.data.checkedNodeIds; + var allLeafIds = leafNodes.map(function (node) { + return node.nodeId; + }); + // 全部未选中 0 + // 全部选中 1 + // 部分选中 2 + var checked = 0; + for (var i = 0; i < allLeafIds.length; i++) { + var child = allLeafIds[i]; + if (checked === 2) { + break; + } + if (checkedNodeIds.indexOf(child) !== -1) { + if (i > 0 && checked !== 1) { + checked = 2; + } else { + checked = 1; + } + } else { + // 当全部选中时,则改为部分选中,否则全部未选中 + checked = checked === 1 ? 2 : 0; + } + } + return checked; + } + }; + + function Cascader(config) { + this.config = $.extend(true, { + elem: '', //绑定元素 + value: null, //预设值 + options: [], //可选项数据源,键名可通过 Props 属性配置 + empty: '暂无数据', //无匹配选项时的内容 + placeholder: '请选择',//输入框占位文本 + disabled: false, //是否禁用 + clearable: false, //是否支持清空选项 + showAllLevels: true, //输入框中是否显示选中值的完整路径 + collapseTags: false, //多选模式下是否折叠Tag + minCollapseTagsNumber: 1, //最小折叠标签数 + separator: ' / ', //选项分隔符 + filterable: false, //是否可搜索选项 + filterMethod: function (node, keyword) { + return node.path.some(function (node) { + return node.label.indexOf(keyword) !== -1; + }); + }, //自定义搜索逻辑,第一个参数是节点node,第二个参数是搜索关键词keyword,通过返回布尔值表示是否命中 + debounce: 300, //搜索关键词输入的去抖延迟,毫秒 + beforeFilter: function (value) { + return true; + },//筛选之前的钩子,参数为输入的值,若返回 false,则停止筛选 + popperClass: '', // 自定义浮层类名 string + extendClass: false, //继承class样式 + extendStyle: false, //继承style样式 + disabledFixed: false, //固定禁用项,使禁用项不被清理删除,禁用项只能通过函数添加或初始值添加,默认禁用项不可被函数或初始值添加 + maxSize: 0, // 多选选中的最大数量,0表示不限制 + props: { + strictMode: false, //严格模式,设置value严格按照层级结构.例如:[[1,2,3],[1,2,4]] + expandTrigger: 'click', //次级菜单的展开方式 string click / hover 'click' + multiple: false, //是否多选 boolean - false + checkStrictly: false, //是否严格的遵守父子节点不互相关联 boolean - false + lazy: false, //是否动态加载子节点,需与 lazyLoad 方法结合使用 boolean - false + lazyLoad: function (node, resolve) { + }, //加载动态数据的方法,仅在 lazy 为 true 时有效 function(node, resolve),node为当前点击的节点,resolve为数据加载完成的回调(必须调用) + value: 'value', //指定选项的值为选项对象的某个属性值 string — 'value' + label: 'label', //指定选项标签为选项对象的某个属性值 string — 'label' + children: 'children', //指定选项的子选项为选项对象的某个属性值 string — 'children' + disabled: 'disabled', //指定选项的禁用为选项对象的某个属性值 string — 'disabled' + leaf: 'leaf' //指定选项的叶子节点的标志位为选项对象的某个属性值 string — 'leaf' + } + }, config); + this.data = { + nodeId: 1, //nodeId的自增值 + nodes: [], //存储Node对象 + menuData: [], //压入菜单的数据 + activeNodeId: null, //存放NodeId + activeNode: null, //存放Node + checkedNodeIds: [], //存放多个NodeId + checkedNodes: [] //存放多个Node + }; + // 面板是否展开 + this.showPanel = false; + this.event = { + // 值变更事件 + change: [], + // 打开事件 + open: [], + // 关闭事件 + close: [] + } + // 是否正在搜索中 + this.filtering = false; + // 初始化 + this._init(); + // 面板关闭事件id + this.closeEventId = 0; + // 是否进入maxSize模式 + this._maxSizeMode = false; + } + + Cascader.prototype = { + constructor: Cascader, + get props() { + return this.config.props; + }, + get isFiltering() { + return this.filtering; + }, + set isFiltering(filtering) { + if (this.filtering === filtering) { + return; + } + this.filtering = !!filtering; + var $panel = this.$panel; + if (this.filtering) { + $panel.find('.el-cascader-panel').hide(); + $panel.find('.el-cascader__suggestion-panel').show(); + } else { + $panel.find('.el-cascader-panel').show(); + $panel.find('.el-cascader__suggestion-panel').hide(); + this.$tagsInput && this.$tagsInput.val('') + } + }, + set maxSizeMode(maxSizeMode) { + if (this._maxSizeMode !== maxSizeMode) { + this._maxSizeMode = maxSizeMode; + this.refreshMenu(); + } + }, + icons: { + from: 'layui-icon', + down: 'layui-icon-down', + close: 'layui-icon-close', + right: 'layui-icon-right', + ok: 'layui-icon-ok', + loading: 'layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop' + }, + // 初始化 + _init: function () { + this._checkConfig(); + // 初始化输入框 + this._initInput(); + // 初始化面板 + this._initPanel(); + // 初始化选项值 + this.setOptions(this.config.options); + var self = this; + // 监听滚动条 + $(window).scroll(function () { + self._resetXY(); + }); + // 监听窗口 + $(window).resize(function () { + self._resetXY(); + }); + // 点击事件,展开面板 + this.$div.click(function (event) { + if (self.config.disabled) { + return; + } + var show = self.showPanel; + if (!show) { + self.open(); + } else { + self.close(); + } + }); + }, + /** + * 检查配置 + * @private + */ + _checkConfig: function () { + var elem = this.config.elem; + if (!elem || $(elem).length === 0) { + throw new Error("缺少elem节点选择器"); + } + var maxSize = this.config.maxSize; + if (typeof maxSize !== 'number' || maxSize < 0) { + throw new Error("maxSize应是一个大于等于0的有效的number值"); + } + if (!Array.isArray(this.config.options)) { + throw new Error("options不是一个有效的数组"); + } + }, + /** + * 初始化根目录 + * @private + */ + _initRoot: function () { + var lazy = this.props.lazy; + var lazyLoad = this.props.lazyLoad; + var self = this; + var nodes = this.data.nodes; + if (nodes.length > 0 || !lazy) { + this._appendMenu(nodes, 0); + } else if (lazy) { + this._appendMenu(nodes, 0); + lazyLoad({ + root: true, + level: 0 + }, function (nodes) { + self.data.nodes = self.initNodes(nodes, 0, null); + self._appendMenu(self.data.nodes, 0); + }); + } + }, + /** + * 设置选项值 + * @param options + */ + setOptions: function (options) { + this.config.options = options; + // 初始化节点 + this.data.nodes = this.initNodes(options, 0, null); + // 初始化根目录 + this._initRoot(); + // 初始化值 + this.setValue(this.config.value); + }, + // 面板定位 + _resetXY: function () { + var $div = this.$div; + var offset = $div.offset(); + var $panel = this.$panel; + if ($panel) { + var windowHeight = window.innerHeight; + var windowWidth = window.innerWidth; + var panelHeight = $panel.height(); + var panelWidth = $panel.width(); + var divHeight = $div.height(); + var boundingClientRect = $div[0].getBoundingClientRect(); + var $arrow = $panel.find('.popper__arrow'); + + // 距离右边界的偏差值 + var offsetDiff = Math.min(windowWidth - boundingClientRect.x - panelWidth - 5, 0); + + var bottomHeight = windowHeight - (boundingClientRect.top + divHeight); + if (bottomHeight < panelHeight && boundingClientRect.top > panelHeight + 20) { + $panel.attr('x-placement', 'top-start') + // 向上 + $panel.css({ + top: offset.top - 20 - panelHeight + 'px', + left: offset.left + offsetDiff + 'px' + }); + } else { + $panel.attr('x-placement', 'bottom-start'); + // 距离底部边界的偏差值 + var yOffset = Math.max(panelHeight - (windowHeight - boundingClientRect.y - divHeight - 15), 0); + // 向下 + $panel.css({ + top: offset.top + divHeight - yOffset + 'px', + left: offset.left + offsetDiff + 'px' + }); + } + // 箭头偏移 + $arrow.css("left", 35 - offsetDiff + "px"); + } + }, + get $menus() { + return this.$panel && this.$panel.find('.el-cascader-panel .el-cascader-menu'); + }, + // 初始化输入框 + _initInput: function () { + var $e = $(this.config.elem); + var self = this; + // 当绑定的元素带有value属性,并且对象未设置值时,设置一个初始值 + if (this.config.value === null && $e.attr('value')) { + this.config.value = $e.attr('value'); + } + var placeholder = this.config.placeholder; + var fromIcon = this.icons.from; + var downIcon = this.icons.down; + var multiple = this.props.multiple; + var extendClass = this.config.extendClass; + var extendStyle = this.config.extendStyle; + + this.$div = $('
    '); + if (extendStyle) { + var style = $e.attr('style'); + if (style) { + this.$div.attr('style', style); + } + } + if (extendClass) { + var className = $e.attr('class'); + if (className) { + className.split(' ').forEach(function (name) { + self.$div.addClass(name); + }); + } + } + this.$input = $('
    ' + + '' + + '' + + '' + + '' + + '' + + '
    ') + this.$div.append(this.$input); + this.$inputRow = this.$input.find('.el-input__inner'); + // 多选标签 + if (multiple) { + this.$tags = $('
    '); + this.$div.append(this.$tags); + } + this._initHideElement($e); + // 替换元素 + $e.replaceWith(this.$div); + this.$icon = this.$input.find('i'); + this._initFilterableInputEvent(); + this.disabled(this.config.disabled); + }, + /** + * 初始化隐藏元素input,主要用于layui的表单验证 + * @param $e + * @private + */ + _initHideElement: function ($e) { + // 保存原始元素 + var attributes = $e[0].attributes; + var $input = $(''); + var keys = Object.keys(attributes); + for (var key in keys) { + var attribute = attributes[key]; + $input.attr(attribute.name, attribute.value); + } + $input.hide(); + $input.attr('type', 'hidden') + this.$ec = $input; + $e.before($input); + }, + /** + * 初始化可搜索监听事件 + * @private + */ + _initFilterableInputEvent: function () { + var filterable = this.config.filterable; + if (!filterable) { + return; + } + var timeoutID; + var multiple = this.props.multiple; + var debounce = this.config.debounce; + var placeholder = this.config.placeholder; + var beforeFilter = this.config.beforeFilter; + var filterMethod = this.config.filterMethod; + var checkStrictly = this.props.checkStrictly; + var self = this; + + function filter(event) { + var input = this; + if (timeoutID) { + clearTimeout(timeoutID); + } + timeoutID = setTimeout(function () { + timeoutID = null; + var val = $(input).val(); + if (!val) { + self.isFiltering = false; + return; + } + self.open(); + if (typeof beforeFilter === 'function' && beforeFilter(val)) { + self.isFiltering = true; + var nodes = self.getNodes(); + var filterNodes = nodes.filter(function (node) { + var disabled; + if (checkStrictly) { + disabled = node.disabled; + } else { + disabled = node.path.some(function (node) { + return node.disabled; + }); + } + if ((node.leaf || checkStrictly) && !disabled) { + if (typeof filterMethod === 'function' && filterMethod(node, val)) { + // 命中 + return true; + } + } + return false; + }); + self._setSuggestionMenu(filterNodes); + } + }, debounce); + } + + if (multiple) { + // 多选可搜索 + this.$tagsInput = $(''); + var $tagsInput = this.$tagsInput; + this.$tags.append($tagsInput); + $tagsInput.on('keydown', filter); + $tagsInput.click(function (event) { + if (self.isFiltering) { + event.stopPropagation(); + } + }); + } else { + var $inputRow = this.$inputRow; + // 单选可搜索 + $inputRow.removeAttr('readonly'); + $inputRow.on('keydown', filter); + $inputRow.click(function (event) { + if (self.isFiltering) { + event.stopPropagation(); + } + }); + } + }, + // 初始化面板(panel(1)) + _initPanel: function () { + var $panel = this.$panel; + var popperClass = this.config.popperClass || ''; + if (!$panel) { + // z-index:解决和layer.open默认19891016的冲突 + this.$panel = $(''); + $panel = this.$panel; + $panel.appendTo('body'); + $panel.click(function (event) { + // 阻止事件冒泡 + event.stopPropagation(); + }); + // 初始化可搜索面板 + this._initSuggestionPanel(); + } + }, + /** + * 添加菜单(panel(1)->menu(n)) + * @param nodes 当前层级数据 + * @param level 层级,从0开始 + * @param parentNode 父级节点 + * @param _menuItem 刷新时,传入的当前菜单的item数据 + * @private + */ + _appendMenu: function (nodes, level, parentNode, _menuItem) { + this._removeMenu(level); + + if (parentNode && parentNode.leaf) { + return; + } + + var menuData = this.data.menuData; + var $div = $(''); + // 重新添加菜单 + this.$panel.find('.el-cascader-panel').append($div); + // 渲染细项 + this._appendLi($div, nodes); + var menuItem = {nodes: nodes, level: level, parentNode: parentNode, scrollbar: {top: 0, left: 0}}; + if (_menuItem) { + menuItem.scrollbar = _menuItem.scrollbar + } + // 渲染滚动条 + this._initScrollbar($div, menuItem); + // 重新定位面板 + this._resetXY(); + menuData.push(menuItem); + }, + /** + * 移除菜单 + * @param level + * @private + */ + _removeMenu: function(level) { + // 除了上一层的所有菜单全部移除 + var number = level - 1; + if (number !== -1) { + this.$panel.find('.el-cascader-panel .el-cascader-menu:gt(' + number + ')').remove(); + } else { + this.$panel.find('.el-cascader-panel .el-cascader-menu').remove(); + } + // 保存菜单数据 + var menuData = this.data.menuData; + if (menuData.length > level) { + menuData.splice(level, menuData.length - level); + } + }, + /** + * 添加细项(panel(1)->menu(n)->li(n)) + * @param $menu 当前菜单对象 + * @param nodes 当前层级数据 + * @private + */ + _appendLi: function ($menu, nodes) { + var $list = $menu.find('.el-cascader-menu__list'); + if (!nodes || nodes.length === 0) { + var isEmpty = this.config.empty; + $list.append('
    ' + isEmpty + '
    '); + return; + } + $.each(nodes, function (index, node) { + node.bind($list); + }); + }, + /** + * 刷新菜单面板 + */ + refreshMenu: function () { + // 先复制一个数组,避免刷新菜单时,数组的数据被改变 + var data = this.data.menuData.concat([]); + var self = this; + data.forEach(function (data) { + self._appendMenu(data.nodes, data.level, data.parentNode, data); + }) + }, + /** + * 初始化可搜索面板 + * @private + */ + _initSuggestionPanel: function () { + var filterable = this.config.filterable; + if (!filterable) { + return; + } + var $suggestionPanel = this.$suggestionPanel; + if (!$suggestionPanel) { + this.$suggestionPanel = $(''); + $suggestionPanel = this.$suggestionPanel; + this.$panel.find('.popper__arrow').before($suggestionPanel); + $suggestionPanel.click(function (event) { + // 阻止事件冒泡 + event.stopPropagation(); + }); + } + }, + /** + * 设置可搜索菜单 + * @param nodes + * @private + */ + _setSuggestionMenu: function (nodes) { + var $suggestionPanel = this.$suggestionPanel; + var $list = $suggestionPanel.find('.el-cascader__suggestion-list'); + $list.empty(); + $suggestionPanel.find('.el-scrollbar__bar').remove(); + if (!nodes || nodes.length === 0) { + $list.append('
  • 无匹配数据
  • '); + return; + } + $.each(nodes, function (index, node) { + node.bindSuggestion($list); + }); + this._initScrollbar($suggestionPanel,{scrollbar: {top: 0, left: 0}}); + this._resetXY(); + }, + /** + * 初始化节点数据 + * @param data 原始数据 + * @param level 层级 + * @param parentNode 父级节点 + * @returns {*[]} + */ + initNodes: function (data, level, parentNode) { + var nodes = []; + for (var key in data) { + var datum = data[key]; + var node = new Node(datum, this, level, parentNode); + nodes.push(node); + if (node.children && node.children.length > 0) { + node.setChildren(this.initNodes(node.children, level + 1, node)); + } + } + return nodes; + }, + /** + * 设置单选值 + * @param nodeId 节点id + * @param node 节点对象 + * @private + */ + _setActiveValue: function (nodeId, node) { + if (this.data.activeNodeId !== nodeId) { + var activeNode = this.data.activeNode; + this.data.activeNodeId = nodeId; + this.data.activeNode = node; + activeNode && activeNode.transferParent(function (node) { + node.syncStyle(); + }, true); + node && node.transferParent(function (node) { + node.syncStyle(); + }, true); + // 填充路径 + this.change(node && node.value, node); + if (nodeId !== null) { + this._setClear(); + } + } + }, + /** + * 设置多选值 + * @param nodeIds 值数组 + * @param nodes 节点数组 + * @private + */ + _setCheckedValue: function (nodeIds, nodes) { + var checkedNodes = this.data.checkedNodes; + var maxSize = this.config.maxSize; + var maxSizeMode; + if (nodeIds.length > 0 && maxSize !== 0 && nodeIds.length >= maxSize) { + nodeIds = nodeIds.slice(0, maxSize); + nodes = nodes.slice(0, maxSize); + maxSizeMode = true + } else { + maxSizeMode = false + } + this.data.checkedNodeIds = nodeIds || []; + this.data.checkedNodes = nodes || []; + var syncPath = []; + var syncNodeIds = []; + checkedNodes.forEach(function (node) { + node.path.forEach(function (node) { + if (syncNodeIds.indexOf(node.nodeId) === -1) { + syncPath.push(node); + syncNodeIds.push(node.nodeId); + } + }); + }); + nodes.forEach(function (node) { + node.path.forEach(function (node) { + if (syncNodeIds.indexOf(node.nodeId) === -1) { + syncPath.push(node); + syncNodeIds.push(node.nodeId); + } + }); + }); + syncPath.forEach(function (node) { + node.syncStyle(); + }); + // 填充路径 + this.change(nodes.map(function (node) { + return node.value; + }), nodes); + this._setClear(); + this.maxSizeMode = maxSizeMode; + }, + /** + * 设置值 + * @param value + */ + setValue: function (value) { + if (this.data.activeNodeId || this.data.checkedNodeIds.length > 0) { + // 清空值 + this.clearCheckedNodes(); + } + if (!value) { + return; + } + var strictMode = this.props.strictMode; + if (strictMode) { + if (!Array.isArray(value)) { + throw new Error("严格模式下,value必须是一个包含父子节点数组结构."); + } + } + var nodes = this.getNodes(this.data.nodes); + var checkStrictly = this.props.checkStrictly; + var multiple = this.props.multiple; + var disabledFixed = this.config.disabledFixed; + if (multiple) { + var paths = nodes.filter(function (node) { + if ((checkStrictly || node.leaf) && (!node.disabled || disabledFixed)) { + if (strictMode) { + // 严格模式下 + // some:命中一个就为true + // every:全部命中为true + return value.some(function (levelValue) { + if (!Array.isArray(levelValue)) { + throw new Error("多选严格模式下,value必须是一个二维数组结构."); + } + var path = node.path; + return levelValue.length === path.length && levelValue.every(function (rowValue, index) { + return path[index].value === rowValue; + }); + }) + } else { + return value.indexOf(node.value) !== -1; + } + } + return false; + }); + var nodeIds = paths.map(function (node) { + return node.nodeId; + }); + this._setCheckedValue(nodeIds, paths); + // 展开第一个节点 + if (paths.length > 0) { + var first = paths[0]; + first.expandPanel(); + } + } else { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if ((checkStrictly || node.leaf)) { + var is = false; + if (strictMode) { + // 严格模式下 + // every:全部命中为true + var path = node.path; + is = value.length === path.length && value.every(function (rowValue, index) { + return path[index].value === rowValue; + }); + } else if (node.value === value) { + is = true; + } + if (is) { + this._setActiveValue(node.nodeId, node); + // 展开节点 + node.expandPanel(); + break; + } + } + } + } + }, + /** + * 递归获取扁平的节点 + * @param nodes + * @param container + * @returns {*[]} + */ + getNodes: function (nodes, container) { + if (!container) { + container = []; + } + if (!nodes) { + nodes = this.data.nodes; + } + var self = this; + nodes.forEach(function (node) { + container.push(node); + var children = node.getChildren(); + if (children) { + self.getNodes(children, container); + } + }); + return container; + }, + /** + * 初始化滚动条 + * @param $menu 菜单的dom节点对象 + * @param menuItem 当前菜单数据 + * @private + */ + _initScrollbar: function ($menu, menuItem) { + var $div = $('
    '); + $menu.append($div); + var vertical = $($div[1]).find('.el-scrollbar__thumb'); + var onhoriztal = $($div[0]).find('.el-scrollbar__thumb'); + var scrollbar = $menu.find('.el-scrollbar__wrap'); + var $panel = this.$panel; + var $lis = $menu.find('li'); + var height = Math.max($panel.height(), $menu.height()); + var hScale = (height - 6) / ($lis.height() * $lis.length); + var wScale = $panel.width() / $lis.width(); + + // 滚动条监听事件 + function _scrollbarEvent(scrollTop, scrollLeft) { + if (hScale < 1) { + vertical.css('height', hScale * 100 + '%'); + vertical.css('transform', 'translateY(' + scrollTop / $menu.height() * 100 + '%)'); + } + if (wScale < 1) { + onhoriztal.css('width', wScale * 100 + '%'); + onhoriztal.css('transform', 'translateY(' + scrollLeft / $menu.width() * 100 + '%)'); + } + } + + // 拖动事件 + vertical.mousedown(function (event) { + event.stopImmediatePropagation(); + event.stopPropagation(); + // 禁止文本选择事件 + var selectstart = function () { + return false; + }; + $(document).bind("selectstart", selectstart); + var y = event.clientY; + var scrollTop = scrollbar.scrollTop(); + // 移动事件 + var mousemove = function (event) { + event.stopImmediatePropagation(); + var number = scrollTop + (event.clientY - y) / hScale; + scrollbar.scrollTop(number); + }; + $(document).bind('mousemove', mousemove); + // 鼠标松开事件 + $(document).one('mouseup', function (event) { + event.stopPropagation(); + event.stopImmediatePropagation(); + $(document).off('mousemove', mousemove); + $(document).off('selectstart', selectstart); + }); + }); + // 监听滚动条事件 + scrollbar.scroll(function () { + var scroll = $(this); + menuItem.scrollbar.top = scroll.scrollTop() + menuItem.scrollbar.left = scroll.scrollLeft() + _scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left); + }); + + // 初始化滚动条 + scrollbar.scrollTop(menuItem.scrollbar.top); + _scrollbarEvent(menuItem.scrollbar.top, menuItem.scrollbar.left); + }, + // 填充路径 + _fillingPath: function () { + var multiple = this.props.multiple; + var showAllLevels = this.config.showAllLevels; + var separator = this.config.separator; + var collapseTags = this.config.collapseTags; + var $inputRow = this.$inputRow; + var placeholder = this.config.placeholder; + var self = this; + if (!multiple) { + var activeNode = this.data.activeNode; + var path = activeNode && activeNode.path || []; + if (showAllLevels) { + this._$inputRowSetValue(path.map(function (node) { + return node.label; + }).join(separator)); + } else { + this._$inputRowSetValue(activeNode && activeNode.label || ""); + } + } else { + // 复选框 + + // 删除标签 + this.$tags.find('.el-tag').remove(); + var $tagsInput = this.$tagsInput; + // 清除高度 + $inputRow.css('height', ''); + var checkedNodes = this.data.checkedNodes; + var minCollapseTagsNumber = Math.max(this.config.minCollapseTagsNumber, 1); + if (checkedNodes.length > 0) { + var tags = []; + var paths = checkedNodes; + if (collapseTags) { + // 折叠tags + paths = checkedNodes.slice(0, Math.min(checkedNodes.length, minCollapseTagsNumber)); + } + paths.forEach(function (node) { + tags.push(node.$tag); + }); + // 判断标签是否折叠 + if (collapseTags) { + // 判断标签最小折叠数 + if (checkedNodes.length > minCollapseTagsNumber) { + tags.push(self.get$tag('+ ' + (checkedNodes.length - minCollapseTagsNumber), false)); + } + } + tags.forEach(function (tag) { + if ($tagsInput) { + $tagsInput.before(tag) + } else { + self.$tags.append(tag); + } + }); + } + var tagHeight = self.$tags.height(); + var inputHeight = $inputRow.height(); + if (tagHeight > inputHeight) { + $inputRow.css('height', tagHeight + 4 + 'px'); + } + // 重新定位 + this._resetXY(); + if (checkedNodes.length > 0) { + $inputRow.removeAttr('placeholder'); + $tagsInput && $tagsInput.removeAttr('placeholder', placeholder); + } else { + $inputRow.attr('placeholder', placeholder); + $tagsInput && $tagsInput.attr('placeholder', placeholder); + } + } + }, + /** + * 设置单选输入框的值 + * @param label + * @private + */ + _$inputRowSetValue: function (label) { + label = label || ""; + var $inputRow = this.$inputRow; + $inputRow.attr('value', label); //防止被重置 + $inputRow.val(label); + }, + /** + * 获取复选框标签对象 + * @param label + * @param showCloseIcon 是否显示关闭的icon + * @returns {jQuery|HTMLElement|*} + */ + get$tag: function (label, showCloseIcon) { + var fromIcon = this.icons.from; + var closeIcon = this.icons.close; + var icon = showCloseIcon ? '' : ''; + return $('' + label + '' + icon + ''); + }, + // 设置可清理 + _setClear: function () { + var self = this; + + function enter() { + self.$icon.removeClass(self.icons.down); + self.$icon.addClass(self.icons.close); + } + + function out() { + self.$icon.removeClass(self.icons.close); + self.$icon.addClass(self.icons.down); + } + + self.$div.mouseenter(function () { + enter(); + }); + self.$div.mouseleave(function () { + out(); + }); + self.$icon.off('click'); + var multiple = this.props.multiple; + var clear; + if (multiple) { + clear = this.data.checkedNodeIds.length > 0; + } else { + clear = !!this.data.activeNodeId; + } + if (clear && !this.config.disabled && this.config.clearable) { + self.$icon.one('click', function (event) { + event.stopPropagation(); + self.close(); + self.clearCheckedNodes(); + out(); + self.$icon.off('mouseenter'); + self.$div.off('mouseenter'); + self.$div.off('mouseleave'); + }); + } else { + out(); + self.$icon.off('mouseenter'); + self.$div.off('mouseenter'); + self.$div.off('mouseleave'); + } + }, + // 禁用 + disabled: function (isDisabled) { + this.config.disabled = !!isDisabled; + if (this.config.disabled) { + this.$div.addClass('is-disabled'); + this.$div.find('.el-input--suffix').addClass('is-disabled'); + this.$inputRow.attr('disabled', 'disabled'); + this.$tagsInput && this.$tagsInput.attr('disabled', 'disabled').hide() + } else { + this.$div.removeClass('is-disabled'); + this.$div.find('.el-input--suffix').removeClass('is-disabled'); + this.$inputRow.removeAttr('disabled'); + this.$tagsInput && this.$tagsInput.removeAttr('disabled').show(); + } + // 重新设置是否可被清理 + this._setClear(); + // 重新填充路径 + this._fillingPath(); + }, + /** + * 当选中节点变化时触发 选中节点的值 + * @param value 值 + * @param node 节点 + */ + change: function (value, node) { + var multiple = this.props.multiple; + if (multiple) { + if (value && value.length > 0) { + this.$ec.attr('value', JSON.stringify(value)); + // this.$ec.val(JSON.stringify(value)); + } else { + this.$ec.removeAttr('value'); + // this.$ec.val(''); + } + } else { + this.$ec.attr('value', value || ""); + // this.$ec.val(value); + } + // 填充路径 + this._fillingPath(); + this.event.change.forEach(function (e) { + typeof e === 'function' && e(value, node) + }) + }, + /** + * 当失去焦点时触发 (event: Event) + * @param eventId 不为空时,必须与closeEventId值相等,防止旧事件触发 + */ + close: function (eventId) { + if (this.showPanel && (!eventId || this.closeEventId === eventId)) { + this.showPanel = false; + this.$div.find('.layui-icon-down').removeClass('is-reverse'); + this.$panel.slideUp(100); + this.visibleChange(false); + // 聚焦颜色 + this.$input.removeClass('is-focus'); + // 可搜索 + var filterable = this.config.filterable; + if (filterable) { + this.isFiltering = false; + this._fillingPath(); + } + this.event.close.forEach(function (e) { + typeof e === 'function' && e() + }) + } + }, + /** + * 当获得焦点时触发 (event: Event) + */ + open: function () { + if (!this.showPanel) { + this.showPanel = true; + this.closeEventId++; + var self = this; + // 当前传播事件结束后,添加点击背景关闭面板事件 + setTimeout(function () { + $(document).one('click', self.close.bind(self, self.closeEventId)); + }); + // 重新定位面板 + this._resetXY(); + // 箭头icon翻转 + this.$div.find('.layui-icon-down').addClass('is-reverse'); + this.$panel.slideDown(200); + this.visibleChange(true); + // 聚焦颜色 + this.$input.addClass('is-focus'); + this.event.open.forEach(function (e) { + typeof e === 'function' && e() + }) + } + }, + /** + * 下拉框出现/隐藏时触发 + * @param visible 出现则为 true,隐藏则为 false + */ + visibleChange: function (visible) { + }, + /** + * 在多选模式下,移除Tag时触发 移除的Tag对应的节点的值 + * @param tagValue 节点的值 + * @param node 节点对象 + */ + removeTag: function (tagValue, node) { + }, + /** + * 获取选中的节点值 + * @returns {null|[]} + */ + getCheckedValues: function () { + var strictMode = this.props.strictMode; + if (this.props.multiple) { + var checkedNodes = this.data.checkedNodes; + if (strictMode) { + return checkedNodes.map(function (node) { + return node.path.map(function (node1) { + return node1.value; + }); + }); + } + return checkedNodes.map(function (node) { + return node.value; + }); + } else { + var activeNode = this.data.activeNode; + if (strictMode) { + return activeNode && activeNode.path.map(function (node) { + return node.value; + }) + } + return activeNode && activeNode.value; + } + }, + /** + * 获取选中的节点 + * @returns {null|[]} + */ + getCheckedNodes: function () { + var strictMode = this.props.strictMode; + if (this.props.multiple) { + var checkedNodes = this.data.checkedNodes; + if (strictMode) { + return checkedNodes && checkedNodes.map(function (node) { + return node.path; + }); + } + return checkedNodes; + } else { + var activeNode = this.data.activeNode; + if (strictMode) { + return activeNode && activeNode.path; + } + return activeNode; + } + }, + /** + * 清空选中的节点 + * @param force 强制清理禁用固定节点 + */ + clearCheckedNodes: function (force) { + var multiple = this.props.multiple; + if (multiple) { + var disabledFixed = this.config.disabledFixed; + if (!force && disabledFixed) { + //禁用项被固定,则过滤出禁用项的选值出来 + var checkedNodes = this.data.checkedNodes; + var disNodes = checkedNodes.filter(function (node) { + return node.disabled; + }); + var nodeIds = disNodes.map(function (node) { + return node.nodeId; + }); + this._setCheckedValue(nodeIds, disNodes); + } else { + this._setCheckedValue([], []); + } + } else { + this._setActiveValue(null, null); + } + } + }; + + var thisCas = function () { + var self = this; + return { + /** + * 设置选项值 + * @param options + */ + setOptions: function (options) { + self.setOptions(options); + }, + /** + * 覆盖当前值 + * @param value 单选时传对象,多选时传数组 + */ + setValue: function (value) { + self.setValue(value); + }, + /** + * 当节点变更时,执行回调 + * @param callback function(value,node){} + */ + changeEvent: function (callback) { + self.event.change.push(callback); + }, + /** + * 当面板关闭时,执行回调 + * @param callback function(){} + */ + closeEvent: function (callback) { + self.event.close.push(callback); + }, + /** + * 当面板打开时,执行回调 + * @param callback function(){} + */ + openEvent: function (callback) { + self.event.open.push(callback); + }, + /** + * 禁用组件 + * @param disabled true/false + */ + disabled: function (disabled) { + self.disabled(disabled); + }, + /** + * 收起面板 + */ + close: function () { + self.close(); + }, + /** + * 展开面板 + */ + open: function () { + self.open(); + }, + /** + * 获取选中的节点,如需获取路径,使用node.path获取,将获取各级节点的node对象 + * @returns {[]|*} + */ + getCheckedNodes: function () { + return self.getCheckedNodes(); + }, + /** + * 获取选中的值 + * @returns {[]|*} + */ + getCheckedValues: function () { + return self.getCheckedValues(); + }, + /** + * 清空选中的节点 + * @param force 强制清理禁用固定节点 + */ + clearCheckedNodes: function (force) { + self.clearCheckedNodes(force); + }, + /** + * 展开面板到节点所在的层级 + * @param value 节点值,只能传单个值,不允许传数组 + */ + expandNode: function (value) { + var nodes = self.getNodes(self.data.nodes); + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (node.value === value) { + node.expandPanel(); + break; + } + } + }, + /** + * 获取当前配置副本 + */ + getConfig: function () { + return $.extend(true, {}, self.config); + }, + /** + * 获取数据对象副本 + * @returns {*} + */ + getData: function () { + return $.extend(true, {}, self.data); + } + }; + }; + + exports('layCascader', function (option) { + var ins = new Cascader(option); + return thisCas.call(ins); + }); +});