From 13cc2ada5a80bf15d9752bd0cb537efe871e41f9 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Wed, 7 Feb 2018 18:56:58 +0800
Subject: [PATCH] add select
---
components/_util/props-util.js | 15 +-
components/_util/vnode.js | 3 +
components/vc-select/DropdownMenu.vue | 27 +-
components/vc-select/PropTypes.js | 4 +-
components/vc-select/Select.vue | 1294 ++++++++++++++++++++++++
components/vc-select/SelectTrigger.vue | 195 ++++
components/vc-select/assets/index.less | 502 +++++++++
components/vc-select/demo/combobox.vue | 63 ++
components/vc-select/util.js | 5 +-
examples/routes.js | 2 +-
package.json | 1 +
11 files changed, 2085 insertions(+), 26 deletions(-)
create mode 100644 components/vc-select/assets/index.less
create mode 100644 components/vc-select/demo/combobox.vue
diff --git a/components/_util/props-util.js b/components/_util/props-util.js
index 97a929dad..b01fd9adf 100644
--- a/components/_util/props-util.js
+++ b/components/_util/props-util.js
@@ -3,6 +3,11 @@ const hasProp = (instance, prop) => {
const propsData = $options.propsData || {}
return prop in propsData
}
+const slotHasProp = (slot, prop) => {
+ const $options = slot.componentOptions || {}
+ const propsData = $options.propsData || {}
+ return prop in propsData
+}
const filterProps = (props, propsData = {}) => {
const res = {}
Object.keys(props).forEach((k) => {
@@ -12,7 +17,9 @@ const filterProps = (props, propsData = {}) => {
})
return res
}
-
+const getSlotOptions = (slot) => {
+ return slot.componentOptions.Ctor.options
+}
const getOptionProps = (instance) => {
const { $options = {}, $props = {}} = instance
return filterProps($props, $options.propsData)
@@ -27,5 +34,9 @@ const getComponentFromProp = (instance, prop) => {
return instance.$slots[prop]
}
-export { hasProp, filterProps, getOptionProps, getComponentFromProp }
+const getPropsData = (ele) => {
+ return ele.componentOptions && ele.componentOptions.propsData
+}
+
+export { hasProp, filterProps, getOptionProps, getComponentFromProp, getSlotOptions, slotHasProp, getPropsData }
export default hasProp
diff --git a/components/_util/vnode.js b/components/_util/vnode.js
index ba85697ee..079c31522 100644
--- a/components/_util/vnode.js
+++ b/components/_util/vnode.js
@@ -123,6 +123,9 @@ export function filterEmpty (children = []) {
export function getPropsData (ele) {
return ele.componentOptions && ele.componentOptions.propsData
}
+export function getValueByProp (ele, prop) {
+ return ele.componentOptions && ele.componentOptions.propsData[prop]
+}
export function getEvents (child) {
let events = {}
diff --git a/components/vc-select/DropdownMenu.vue b/components/vc-select/DropdownMenu.vue
index 2d16545cc..750f34cf4 100644
--- a/components/vc-select/DropdownMenu.vue
+++ b/components/vc-select/DropdownMenu.vue
@@ -1,6 +1,5 @@
diff --git a/components/vc-select/SelectTrigger.vue b/components/vc-select/SelectTrigger.vue
index e69de29bb..843eadb39 100644
--- a/components/vc-select/SelectTrigger.vue
+++ b/components/vc-select/SelectTrigger.vue
@@ -0,0 +1,195 @@
+
diff --git a/components/vc-select/assets/index.less b/components/vc-select/assets/index.less
new file mode 100644
index 000000000..3fdf5bd09
--- /dev/null
+++ b/components/vc-select/assets/index.less
@@ -0,0 +1,502 @@
+@selectPrefixCls: rc-select;
+
+.effect() {
+ animation-duration: .3s;
+ animation-fill-mode: both;
+ transform-origin: 0 0;
+}
+
+.@{selectPrefixCls} {
+ box-sizing: border-box;
+ display: inline-block;
+ position: relative;
+ vertical-align: middle;
+ color: #666;
+ line-height: 28px;
+
+ &-allow-clear {
+ .@{selectPrefixCls}-selection--single .@{selectPrefixCls}-selection__rendered {
+ padding-right: 40px;
+ }
+ }
+
+ ul, li {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ > ul > li > a {
+ padding: 0;
+ background-color: #fff;
+ }
+
+ // arrow
+ &-arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ outline: none;
+ b {
+ border-color: #999999 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ width: 0;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ }
+ }
+
+ &-selection {
+ outline: none;
+ user-select: none;
+ -webkit-user-select: none;
+
+ box-sizing: border-box;
+ display: block;
+
+ background-color: #fff;
+ border-radius: 6px;
+ border: 1px solid #d9d9d9;
+
+ &__placeholder {
+ position: absolute;
+ top: 0;
+ color: #aaa;
+ }
+
+ &__clear {
+ font-weight: bold;
+ position: absolute;
+ line-height: 28px;
+
+ &:after {
+ content: '×'
+ }
+ }
+ }
+
+ &-focused &-selection {
+ border-color: #23c0fa;
+ box-shadow: 0 0 2px fadeout(#2db7f5, 20%);
+ }
+
+ &-enabled &-selection {
+ &:hover {
+ border-color: #23c0fa;
+ box-shadow: 0 0 2px fadeout(#2db7f5, 20%);
+ }
+ &:active {
+ border-color: #2db7f5;
+ }
+ }
+
+ &-selection--single {
+ height: 28px;
+ line-height: 28px;
+ cursor: pointer;
+ position: relative;
+
+ .@{selectPrefixCls}-selection-selected-value {
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+
+ .@{selectPrefixCls}-selection__rendered {
+ height: 28px;
+ position: relative;
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ margin-left: 10px;
+ padding-right: 20px;
+ line-height: 28px;
+ }
+
+ .@{selectPrefixCls}-selection__clear {
+ top: 0;
+ right: 20px;
+ }
+ }
+
+ &-disabled {
+ color: #ccc;
+ cursor: not-allowed;
+
+ .@{selectPrefixCls}-selection--single,
+ .@{selectPrefixCls}-selection__choice__remove {
+ cursor: not-allowed;
+ color: #ccc;
+
+ &:hover {
+ cursor: not-allowed;
+ color: #ccc;
+ }
+ }
+ }
+
+ &-search__field__wrap {
+ display: inline-block;
+ }
+
+ &-search__field__placeholder {
+ position: absolute;
+ top: 0;
+ left: 3px;
+ color: #aaa;
+ }
+
+ &-search--inline {
+ width: 100%;
+ .@{selectPrefixCls}-search__field__wrap {
+ width: 100%;
+ }
+ .@{selectPrefixCls}-search__field {
+ border: none;
+ font-size: 100%;
+ //margin-top: 5px;
+ background: transparent;
+ outline: 0;
+ width: 100%;
+ &::-ms-clear {
+ display: none;
+ }
+ }
+ .@{selectPrefixCls}-search__field__mirror {
+ position: absolute;
+ top: -999px;
+ left: 0;
+ white-space: pre;
+ }
+ > i {
+ float: right;
+ }
+ }
+
+ &-enabled&-selection--multiple {
+ cursor: text;
+ }
+
+ &-selection--multiple {
+ min-height: 28px;
+
+ .@{selectPrefixCls}-search--inline {
+ float: left;
+ width: auto;
+ .@{selectPrefixCls}-search__field {
+ &__wrap {
+ width: auto;
+ }
+ width: 0.75em;
+ }
+ }
+
+ .@{selectPrefixCls}-search__field__placeholder {
+ top: 5px;
+ left: 8px;
+ }
+
+ .@{selectPrefixCls}-selection__rendered {
+ position: relative;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-left: 8px;
+ padding-bottom: 2px;
+
+ .@{selectPrefixCls}-selection__choice {
+ margin-top: 4px;
+ line-height: 20px;
+ }
+ }
+
+ .@{selectPrefixCls}-selection__clear {
+ top: 1px;
+ right: 8px;
+ }
+ }
+
+ &-enabled {
+ .@{selectPrefixCls}-selection__choice {
+ cursor: default;
+ &:hover {
+ .@{selectPrefixCls}-selection__choice__remove {
+ opacity: 1;
+ transform: scale(1);
+ }
+ .@{selectPrefixCls}-selection__choice__content {
+ margin-left: -8px;
+ margin-right: 8px;
+ }
+ }
+ }
+
+ .@{selectPrefixCls}-selection__choice__disabled {
+ cursor: not-allowed;
+ &:hover {
+ .@{selectPrefixCls}-selection__choice__content {
+ margin-left: 0;
+ margin-right: 0;
+ }
+ }
+ }
+ }
+
+ & &-selection__choice {
+ background-color: #f3f3f3;
+ border-radius: 4px;
+ float: left;
+ padding: 0 15px;
+ margin-right: 4px;
+ position: relative;
+ overflow: hidden;
+ transition: padding .3s cubic-bezier(0.6, -0.28, 0.735, 0.045), width .3s cubic-bezier(0.6, -0.28, 0.735, 0.045);
+
+ &__content {
+ margin-left: 0;
+ margin-right: 0;
+ transition: margin .3s cubic-bezier(0.165, 0.84, 0.44, 1);
+ }
+
+ &-zoom-enter, &-zoom-appear, &-zoom-leave {
+ .effect();
+ opacity: 0;
+ animation-play-state: paused;
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ }
+
+ &-zoom-leave {
+ opacity: 1;
+ animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
+ }
+
+ &-zoom-enter.@{selectPrefixCls}-selection__choice-zoom-enter-active,
+ &-zoom-appear.@{selectPrefixCls}-selection__choice-zoom-appear-active {
+ animation-play-state: running;
+ animation-name: rcSelectChoiceZoomIn;
+ }
+
+ &-zoom-leave.@{selectPrefixCls}-selection__choice-zoom-leave-active {
+ animation-play-state: running;
+ animation-name: rcSelectChoiceZoomOut;
+ }
+
+ @keyframes rcSelectChoiceZoomIn {
+ 0% {
+ transform: scale(0.6);
+ opacity: 0;
+ }
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+ }
+
+ @keyframes rcSelectChoiceZoomOut {
+ to {
+ transform: scale(0);
+ opacity: 0;
+ }
+ }
+
+ &__remove {
+ color: #919191;
+ cursor: pointer;
+ font-weight: bold;
+ padding: 0 0 0 8px;
+ position: absolute;
+ opacity: 0;
+ transform: scale(0);
+ top: 0;
+ right: 2px;
+ transition: opacity .3s, transform .3s;
+ &:before {
+ content: '×'
+ }
+
+ &:hover {
+ color: #333;
+ }
+ }
+ }
+
+ &-dropdown {
+ background-color: white;
+ border: 1px solid #d9d9d9;
+ box-shadow: 0 0px 4px #d9d9d9;
+ border-radius: 4px;
+ box-sizing: border-box;
+ z-index: 100;
+ left: -9999px;
+ top: -9999px;
+ position: absolute;
+ outline: none;
+
+ &:empty,
+ &-hidden {
+ display: none;
+ }
+
+ &-menu {
+ outline: none;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ z-index: 9999;
+
+ > li {
+ margin: 0;
+ padding: 0;
+ }
+
+ &-item-group-list {
+ margin: 0;
+ padding: 0;
+
+ > li.@{selectPrefixCls}-menu-item {
+ padding-left: 20px;
+ }
+ }
+
+ &-item-group-title {
+ color: #999;
+ line-height: 1.5;
+ padding: 8px 10px;
+ border-bottom: 1px solid #dedede;
+ }
+
+ li&-item {
+ margin: 0;
+ position: relative;
+ display: block;
+ padding: 7px 10px;
+ font-weight: normal;
+ color: #666;
+ white-space: nowrap;
+
+ &-disabled {
+ color: #ccc;
+ cursor: not-allowed;
+ }
+
+ &-selected {
+ color: #666;
+ background-color: #ddd;
+ }
+
+ &-active {
+ background-color: #5897fb;
+ color: white;
+ cursor: pointer;
+ }
+
+ &-divider {
+ height: 1px;
+ margin: 1px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ line-height: 0;
+ }
+ }
+ }
+
+ &-slide-up-enter, &-slide-up-appear {
+ .effect();
+ opacity: 0;
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-play-state: paused;
+ }
+
+ &-slide-up-leave {
+ .effect();
+ opacity: 1;
+ animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+ animation-play-state: paused;
+ }
+
+ &-slide-up-enter&-slide-up-enter-active&-placement-bottomLeft, &-slide-up-appear&-slide-up-appear-active&-placement-bottomLeft {
+ animation-name: rcSelectDropdownSlideUpIn;
+ animation-play-state: running;
+ }
+
+ &-slide-up-leave&-slide-up-leave-active&-placement-bottomLeft {
+ animation-name: rcSelectDropdownSlideUpOut;
+ animation-play-state: running;
+ }
+
+ &-slide-up-enter&-slide-up-enter-active&-placement-topLeft, &-slide-up-appear&-slide-up-appear-active&-placement-topLeft {
+ animation-name: rcSelectDropdownSlideDownIn;
+ animation-play-state: running;
+ }
+
+ &-slide-up-leave&-slide-up-leave-active&-placement-topLeft {
+ animation-name: rcSelectDropdownSlideDownOut;
+ animation-play-state: running;
+ }
+
+ @keyframes rcSelectDropdownSlideUpIn {
+ 0% {
+ opacity: 0;
+ transform-origin: 0% 0%;
+ transform: scaleY(0);
+ }
+ 100% {
+ opacity: 1;
+ transform-origin: 0% 0%;
+ transform: scaleY(1);
+ }
+ }
+ @keyframes rcSelectDropdownSlideUpOut {
+ 0% {
+ opacity: 1;
+ transform-origin: 0% 0%;
+ transform: scaleY(1);
+ }
+ 100% {
+ opacity: 0;
+ transform-origin: 0% 0%;
+ transform: scaleY(0);
+ }
+ }
+
+ @keyframes rcSelectDropdownSlideDownIn {
+ 0% {
+ opacity: 0;
+ transform-origin: 0% 100%;
+ transform: scaleY(0);
+ }
+ 100% {
+ opacity: 1;
+ transform-origin: 0% 100%;
+ transform: scaleY(1);
+ }
+ }
+ @keyframes rcSelectDropdownSlideDownOut {
+ 0% {
+ opacity: 1;
+ transform-origin: 0% 100%;
+ transform: scaleY(1);
+ }
+ 100% {
+ opacity: 0;
+ transform-origin: 0% 100%;
+ transform: scaleY(0);
+ }
+ }
+ }
+
+ &-open {
+ .@{selectPrefixCls}-arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px;
+ }
+ }
+
+}
diff --git a/components/vc-select/demo/combobox.vue b/components/vc-select/demo/combobox.vue
new file mode 100644
index 000000000..0700da7ad
--- /dev/null
+++ b/components/vc-select/demo/combobox.vue
@@ -0,0 +1,63 @@
+
diff --git a/components/vc-select/util.js b/components/vc-select/util.js
index 40dcb3135..c18a9e68a 100644
--- a/components/vc-select/util.js
+++ b/components/vc-select/util.js
@@ -1,12 +1,13 @@
+import { getPropsData, getSlotOptions } from '../_util/props-util'
export function getValuePropValue (child) {
- const props = child.props
+ const props = getPropsData(child)
if ('value' in props) {
return props.value
}
if (child.key) {
return child.key
}
- if (child.type && child.type.isSelectOptGroup && props.label) {
+ if (getSlotOptions(child).isSelectOptGroup && props.label) {
return props.label
}
throw new Error(
diff --git a/examples/routes.js b/examples/routes.js
index 469049595..5e4a0d694 100644
--- a/examples/routes.js
+++ b/examples/routes.js
@@ -3,7 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1]
return {
- component: import(`../components/message/demo/${d}.md`),
+ component: import(`../components/vc-select/demo/${d}.vue`),
}
}
export default [
diff --git a/package.json b/package.json
index abc9a7614..0cfcdd748 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
},
"dependencies": {
"add-dom-event-listener": "^1.0.2",
+ "classnames": "^2.2.5",
"component-classes": "^1.2.6",
"css-animation": "^1.4.1",
"dom-align": "^1.6.7",