From 0178c35de92dedfcbbefd41796482057b13f901d Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 3 Jan 2019 20:51:56 +0800 Subject: [PATCH] perf: input icon grid --- components/grid/Row.jsx | 2 +- components/icon/index.js | 2 +- components/input/Input.jsx | 2 + components/input/TextArea.jsx | 44 ++++++++++++--- components/input/calculateNodeHeight.js | 68 +++++++++++------------- components/input/demo/textarea-resize.md | 28 ++++++++++ package.json | 2 +- types/badge.d.ts | 7 +-- types/cascader.d.ts | 6 +++ 9 files changed, 112 insertions(+), 49 deletions(-) create mode 100644 components/input/demo/textarea-resize.md diff --git a/components/grid/Row.jsx b/components/grid/Row.jsx index 09e77bb1d..a89546212 100644 --- a/components/grid/Row.jsx +++ b/components/grid/Row.jsx @@ -105,7 +105,7 @@ export default { getGutter () { const { gutter } = this if (typeof gutter === 'object') { - for (let i = 0; i <= responsiveArray.length; i++) { + for (let i = 0; i < responsiveArray.length; i++) { const breakpoint = responsiveArray[i] if (this.screens[breakpoint] && gutter[breakpoint] !== undefined) { return gutter[breakpoint] diff --git a/components/icon/index.js b/components/icon/index.js index 31e4ec37a..d6c2cd9d1 100644 --- a/components/icon/index.js +++ b/components/icon/index.js @@ -112,7 +112,7 @@ const Icon = { ` the 'theme' prop '${theme}' will be ignored.`) } computedType = withThemeSuffix( - removeTypeTheme(alias(type)), + removeTypeTheme(alias(computedType)), dangerousTheme || theme || defaultTheme, ) innerNode = ( diff --git a/components/input/Input.jsx b/components/input/Input.jsx index 5f050b285..8863328c8 100644 --- a/components/input/Input.jsx +++ b/components/input/Input.jsx @@ -171,6 +171,8 @@ export default { 'addonAfter', 'prefix', 'suffix', + 'value', + 'defaultValue', ]) const { stateValue, getInputClassName, handleKeyDown, handleChange, $listeners } = this const inputProps = { diff --git a/components/input/TextArea.jsx b/components/input/TextArea.jsx index 1ff5a6cde..a488be4a4 100644 --- a/components/input/TextArea.jsx +++ b/components/input/TextArea.jsx @@ -1,5 +1,6 @@ import omit from 'omit.js' +import ResizeObserver from 'resize-observer-polyfill' import inputProps from './inputProps' import calculateNodeHeight from './calculateNodeHeight' import hasProp from '../_util/props-util' @@ -47,22 +48,53 @@ export default { }, watch: { value (val) { + this.$nextTick(() => { + this.resizeOnNextFrame() + }) this.stateValue = fixControlledValue(val) - if (this.nextFrameActionId) { - clearNextFrameAction(this.nextFrameActionId) + }, + autosize (val) { + if (!val && this.$refs.textArea) { + this.textareaStyles = omit(this.textareaStyles, ['overflowY']) } - this.nextFrameActionId = onNextFrame(this.resizeTextarea) }, }, mounted () { this.$nextTick(() => { this.resizeTextarea() + this.updateResizeObserverHook() if (this.autoFocus) { this.focus() } }) }, + updated () { + this.updateResizeObserverHook() + }, + beforeDestroy () { + if (this.resizeObserver) { + this.resizeObserver.disconnect() + } + }, methods: { + resizeOnNextFrame () { + if (this.nextFrameActionId) { + clearNextFrameAction(this.nextFrameActionId) + } + this.nextFrameActionId = onNextFrame(this.resizeTextarea) + }, + // We will update hooks if `autosize` prop change + updateResizeObserverHook () { + if (!this.resizeObserver && this.$props.autosize) { + // Add resize observer + this.resizeObserver = new ResizeObserver(this.resizeOnNextFrame) + this.resizeObserver.observe(this.$refs.textArea) + } else if (this.resizeObserver && !this.$props.autosize) { + // Remove resize observer + this.resizeObserver.disconnect() + this.resizeObserver = null + } + }, handleKeyDown (e) { if (e.keyCode === 13) { this.$emit('pressEnter', e) @@ -91,9 +123,7 @@ export default { handleTextareaChange (e) { if (!hasProp(this, 'value')) { this.stateValue = e.target.value - this.$nextTick(() => { - this.resizeTextarea() - }) + this.resizeTextarea() } else { this.$forceUpdate() } @@ -126,6 +156,8 @@ export default { 'prefixCls', 'autosize', 'type', + 'value', + 'defaultValue', ]) const textareaProps = { attrs: { ...otherProps, ...$attrs }, diff --git a/components/input/calculateNodeHeight.js b/components/input/calculateNodeHeight.js index c1dcf48ab..12c194e23 100644 --- a/components/input/calculateNodeHeight.js +++ b/components/input/calculateNodeHeight.js @@ -5,15 +5,15 @@ */ const HIDDEN_TEXTAREA_STYLE = ` -min-height:0 !important; -max-height:none !important; -height:0 !important; -visibility:hidden !important; -overflow:hidden !important; -position:absolute !important; -z-index:-1000 !important; -top:0 !important; -right:0 !important + min-height:0 !important; + max-height:none !important; + height:0 !important; + visibility:hidden !important; + overflow:hidden !important; + position:absolute !important; + z-index:-1000 !important; + top:0 !important; + right:0 !important ` const SIZING_STYLE = [ @@ -38,11 +38,9 @@ const computedStyleCache = {} let hiddenTextarea function calculateNodeStyling (node, useCache = false) { - const nodeRef = ( - node.getAttribute('id') || - node.getAttribute('data-reactid') || - node.getAttribute('name') - ) + const nodeRef = (node.getAttribute('id') || + node.getAttribute('data-reactid') || + node.getAttribute('name')) if (useCache && computedStyleCache[nodeRef]) { return computedStyleCache[nodeRef] @@ -50,25 +48,20 @@ function calculateNodeStyling (node, useCache = false) { const style = window.getComputedStyle(node) - const boxSizing = ( + const boxSizing = style.getPropertyValue('box-sizing') || - style.getPropertyValue('-moz-box-sizing') || - style.getPropertyValue('-webkit-box-sizing') - ) + style.getPropertyValue('-moz-box-sizing') || + style.getPropertyValue('-webkit-box-sizing') - const paddingSize = ( + const paddingSize = parseFloat(style.getPropertyValue('padding-bottom')) + - parseFloat(style.getPropertyValue('padding-top')) - ) + parseFloat(style.getPropertyValue('padding-top')) - const borderSize = ( + const borderSize = parseFloat(style.getPropertyValue('border-bottom-width')) + - parseFloat(style.getPropertyValue('border-top-width')) - ) + parseFloat(style.getPropertyValue('border-top-width')) - const sizingStyle = SIZING_STYLE - .map(name => `${name}:${style.getPropertyValue(name)}`) - .join(';') + const sizingStyle = SIZING_STYLE.map(name => `${name}:${style.getPropertyValue(name)}`).join(';') const nodeInfo = { sizingStyle, @@ -105,10 +98,10 @@ export default function calculateNodeHeight ( // Copy all CSS properties that have an impact on the height of the content in // the textbox - const { - paddingSize, borderSize, - boxSizing, sizingStyle, - } = calculateNodeStyling(uiTextNode, useCache) + const { paddingSize, borderSize, boxSizing, sizingStyle } = calculateNodeStyling( + uiTextNode, + useCache, + ) // Need to have the overflow attribute to hide the scrollbar otherwise // text-lines will not calculated properly as the shadow will technically be @@ -116,22 +109,22 @@ export default function calculateNodeHeight ( hiddenTextarea.setAttribute('style', `${sizingStyle};${HIDDEN_TEXTAREA_STYLE}`) hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || '' - let minHeight = -Infinity - let maxHeight = Infinity + let minHeight = Number.MIN_SAFE_INTEGER + let maxHeight = Number.MAX_SAFE_INTEGER let height = hiddenTextarea.scrollHeight let overflowY if (boxSizing === 'border-box') { - // border-box: add border, since height = content + padding + border + // border-box: add border, since height = content + padding + border height = height + borderSize } else if (boxSizing === 'content-box') { - // remove padding, since height = content + // remove padding, since height = content height = height - paddingSize } if (minRows !== null || maxRows !== null) { - // measure height of a textarea with a single row - hiddenTextarea.value = '' + // measure height of a textarea with a single row + hiddenTextarea.value = ' ' const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize if (minRows !== null) { minHeight = singleRowHeight * minRows @@ -150,6 +143,7 @@ export default function calculateNodeHeight ( } } // Remove scroll bar flash when autosize without maxRows + // donot remove in vue if (!maxRows) { overflowY = 'hidden' } diff --git a/components/input/demo/textarea-resize.md b/components/input/demo/textarea-resize.md new file mode 100644 index 000000000..b853cd8e7 --- /dev/null +++ b/components/input/demo/textarea-resize.md @@ -0,0 +1,28 @@ + +#### 文本域 +用于多行输入。 + + + +#### TextArea +For multi-line input. + + +```html + + +``` diff --git a/package.json b/package.json index a000f2d0a..f8cb084ca 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "mutationobserver-shim": "^0.3.2", "omit.js": "^1.0.0", "raf": "^3.4.0", - "resize-observer-polyfill": "^1.5.0", + "resize-observer-polyfill": "^1.5.1", "shallow-equal": "^1.0.0", "shallowequal": "^1.0.2", "vue-ref": "^1.0.3", diff --git a/types/badge.d.ts b/types/badge.d.ts index 7d5ff850b..0da61af02 100644 --- a/types/badge.d.ts +++ b/types/badge.d.ts @@ -3,13 +3,14 @@ // Definitions: https://github.com/vueComponent/ant-design-vue/types import { AntdComponent } from './component'; +import { VNode } from 'vue'; export declare class Badge extends AntdComponent { /** - * Number to show in badge - * @type number | string + * Number to show in badge, support slot + * @type number | string | VNode */ - count: number | string; + count: number | string | VNode; /** * to display a red dot instead of count diff --git a/types/cascader.d.ts b/types/cascader.d.ts index f239d95fe..30e8e6f04 100644 --- a/types/cascader.d.ts +++ b/types/cascader.d.ts @@ -38,6 +38,12 @@ export interface ShowSearchType { * @type boolean */ matchInputWidth?: boolean; + + /** + * Set the count of filtered items + * @type number | false + */ + limit?: number | false; } export declare class Cascader extends AntdComponent {