From 532a6ce65f30f47fc068418a9fb1494e5bc1349f Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Tue, 28 Sep 2021 02:41:48 +0800 Subject: [PATCH] fix(grid-item): no resposive behavior, closes #1220 --- CHANGELOG.en-US.md | 6 ++ CHANGELOG.zh-CN.md | 6 ++ package.json | 2 +- src/grid/demos/enUS/index.demo-entry.md | 6 +- src/grid/demos/enUS/responsive-item.demo.md | 52 +++++++++++++++++ src/grid/demos/enUS/responsive.demo.md | 6 +- src/grid/demos/zhCN/grid-basic-debug.demo.md | 6 ++ src/grid/demos/zhCN/index.demo-entry.md | 13 +++-- src/grid/demos/zhCN/responsive-item.demo.md | 52 +++++++++++++++++ src/grid/demos/zhCN/responsive.demo.md | 6 +- src/grid/src/Grid.tsx | 61 +++++++++++++------- 11 files changed, 184 insertions(+), 32 deletions(-) create mode 100644 src/grid/demos/enUS/responsive-item.demo.md create mode 100644 src/grid/demos/zhCN/responsive-item.demo.md diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 23c7b942238..2ed64e73969 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -5,6 +5,12 @@ ### Fixes - Fix `n-data-table` ellipsis not show when last column not set ellipsis, closes [#934](https://github.com/TuSimple/naive-ui/issues/934). +- Fix `n-grid-item` won't work with responsive config. + +### Feats + +- `n-grid-item` won't display when `span` is 0, closes [#1220](https://github.com/TuSimple/naive-ui/issues/1220). +- `n-grid` add `item-responsive` prop. ## 2.19.2 (2021-09-26) diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 347cdb8a9c6..686c3714633 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -5,6 +5,12 @@ ### Fixes - Fix `n-data-table` 当最后一列未设置 `ellipsis` 时省略失效,关闭 [#934](https://github.com/TuSimple/naive-ui/issues/934) +- Fix `n-grid-item` 响应式不生效 + +### Feats + +- `n-grid-item` 在 `span` 为 0 的时候隐藏,关闭 [#1220](https://github.com/TuSimple/naive-ui/issues/1220) +- `n-grid` 新增 `item-responsive` 属性 ## 2.19.2 (2021-09-26) diff --git a/package.json b/package.json index c2432d245d1..d7b5e1cb05f 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "highlight.js": "^11.0.1", "lodash": "^4.17.21", "lodash-es": "^4.17.21", - "seemly": "^0.3.1", + "seemly": "^0.3.2", "treemate": "^0.3.8", "vdirs": "^0.1.4", "vfonts": "^0.1.0", diff --git a/src/grid/demos/enUS/index.demo-entry.md b/src/grid/demos/enUS/index.demo-entry.md index 125e757244c..186987ced1e 100644 --- a/src/grid/demos/enUS/index.demo-entry.md +++ b/src/grid/demos/enUS/index.demo-entry.md @@ -9,6 +9,7 @@ basic gap offset responsive +responsive-item collapse ``` @@ -22,6 +23,7 @@ collapse | collapsed | `boolean` | `false` | Whether to fold by default. | | collapsed-rows | `number` | `1` | The number of rows displayed by default. | | responsive | `'self' \| 'screen'` | `'screen'` | `'self'` triggers responsive layout by its own width. `'screen'` triggers responsive layout by viewport's witdh. | +| item-responsive | `boolean` | `false` | Whether the grid item is responsive. | | x-gap | `number \| ResponsiveDescription` | `0` | Horizontal gap. | | y-gap | `number \| ResponsiveDescription` | `0` | Vertical gap. | @@ -29,8 +31,8 @@ collapse | Name | Type | Default | Description | | --- | --- | --- | --- | -| offset | `number` | `0` | The number of intervals to the left of the grid. | -| span | `number` | `1` | The number of columns occupied by the grid. | +| offset | `number \| ResponsiveDescription` | `0` | The number of intervals to the left of the grid. | +| span | `number \| ResponsiveDescription` | `1` | The number of columns occupied by the grid. The grid item would be hidden if it's 0. | | suffix | `boolean` | `false` | Grid suffix. | ## Slots diff --git a/src/grid/demos/enUS/responsive-item.demo.md b/src/grid/demos/enUS/responsive-item.demo.md new file mode 100644 index 00000000000..c79d601113e --- /dev/null +++ b/src/grid/demos/enUS/responsive-item.demo.md @@ -0,0 +1,52 @@ +# Responsive Grid Item + +`n-grid-item`'s `span`, `offset` support responsive config. + +When `span` is 0, `n-grid-item` won't be displayed. + +```html +Self Responsive + + +
+ 0 ~ 400px: hidden
+ 400 ~ 600px: span 1
+ 600 ~ 800px: span 2
+ 800px 以上: span 3 +
+
+ +
2
+
+
+Screen Responsive + + +
+ m-: hidden
+ m ~ l: span 1
+ l+: span 2 +
+
+ +
2
+
+
+``` + +```css +.light-green { + display: flex; + align-items: center; + justify-content: center; + height: 200px; + background-color: rgba(0, 128, 0, 0.12); +} +.green { + display: flex; + align-items: center; + justify-content: center; + height: 200px; + background-color: rgba(0, 128, 0, 0.24); +} +``` diff --git a/src/grid/demos/enUS/responsive.demo.md b/src/grid/demos/enUS/responsive.demo.md index 23834c8b6fe..26c55590542 100644 --- a/src/grid/demos/enUS/responsive.demo.md +++ b/src/grid/demos/enUS/responsive.demo.md @@ -1,6 +1,6 @@ -# Responsive +# Responsive Columns -`n-grid`'s `cols`, `x-gap`, `y-gap` and `n-grid-item`'s `span`, `offset` support responsive config. +`n-grid`'s `cols`, `x-gap`, `y-gap` support responsive config. `n-grid` has 2 responsive mode. The inner `n-grid-item` follows its parent's mode. @@ -8,6 +8,8 @@ Responsive props in `self`(default) mode are controlled by `n-grid`'s own width. Responsive props in `screen`(default) mode are controlled by viewport width of the browser. There are `xs` `s` `m` `l` `xl` `2xl` screen width to choose. A responsive `cols` looks like `2 s:3 m:4 l:5 xl:6 2xl:7`. +The default screen config is `xs < 640 <= s < 1024 <= m < 1280 <= l < 1536 <= xl < 1920 <= xxl`. + ```html Self Responsive diff --git a/src/grid/demos/zhCN/grid-basic-debug.demo.md b/src/grid/demos/zhCN/grid-basic-debug.demo.md index 7be4732c4c1..ce55b7a0290 100644 --- a/src/grid/demos/zhCN/grid-basic-debug.demo.md +++ b/src/grid/demos/zhCN/grid-basic-debug.demo.md @@ -12,9 +12,15 @@
0
+ +
0.5
+
1
+ +
1.5
+
2
diff --git a/src/grid/demos/zhCN/index.demo-entry.md b/src/grid/demos/zhCN/index.demo-entry.md index b8d2bab9ea7..8230eafec1e 100644 --- a/src/grid/demos/zhCN/index.demo-entry.md +++ b/src/grid/demos/zhCN/index.demo-entry.md @@ -9,7 +9,9 @@ basic gap offset responsive +responsive-item collapse +grid-basic-debug ``` ## Props @@ -22,16 +24,17 @@ collapse | collapsed | `boolean` | `false` | 是否默认折叠 | | collapsed-rows | `number` | `1` | 默认展示的行数 | | responsive | `'self' \| 'screen'` | `'self'` | `'self'` 根据自身宽度进行响应式布局,`'screen'` 根据屏幕断点进行响应式布局 | +| item-responsive | `boolean` | `false` | 子元素是否可具有响应式宽度 | | x-gap | `number \| ResponsiveDescription` | `0` | 横向间隔槽 | | y-gap | `number \| ResponsiveDescription` | `0` | 纵向间隔槽 | ### GridItem Props -| 名称 | 类型 | 默认值 | 说明 | -| ------ | --------- | ------- | ------------------ | -| offset | `number` | `0` | 栅格左侧的间隔格数 | -| span | `number` | `1` | 栅格占据的列数 | -| suffix | `boolean` | `false` | 栅格后缀 | +| 名称 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| offset | `number \| ResponsiveDescription` | `0` | 栅格左侧的间隔格数, | +| span | `number \| ResponsiveDescription` | `1` | 栅格占据的列数,为 0 的时候会隐藏 | +| suffix | `boolean` | `false` | 栅格后缀 | ## Slots diff --git a/src/grid/demos/zhCN/responsive-item.demo.md b/src/grid/demos/zhCN/responsive-item.demo.md new file mode 100644 index 00000000000..c8968c49c0c --- /dev/null +++ b/src/grid/demos/zhCN/responsive-item.demo.md @@ -0,0 +1,52 @@ +# 响应式栅格项 + +`n-grid-item` 的 `span` `offset` 支持响应式参数配置。需要在 `n-grid` 上设定 `item-responsive`。 + +当 `span` 为 0 的时候,`n-grid-item` 不会被显示。 + +```html +Self 响应式 + + +
+ 0~400px:不显示
+ 400~600px:占据空间 1
+ 600~800px:占据空间 2
+ 800px 以上:占据空间 3 +
+
+ +
2
+
+
+Screen 响应式 + + +
+ m 以下:不显示
+ m 到 l:占据空间 1
+ l 以上:占据空间 2 +
+
+ +
2
+
+
+``` + +```css +.light-green { + display: flex; + align-items: center; + justify-content: center; + height: 200px; + background-color: rgba(0, 128, 0, 0.12); +} +.green { + display: flex; + align-items: center; + justify-content: center; + height: 200px; + background-color: rgba(0, 128, 0, 0.24); +} +``` diff --git a/src/grid/demos/zhCN/responsive.demo.md b/src/grid/demos/zhCN/responsive.demo.md index 13609ee1fcf..de8681f79ea 100644 --- a/src/grid/demos/zhCN/responsive.demo.md +++ b/src/grid/demos/zhCN/responsive.demo.md @@ -1,6 +1,6 @@ -# 响应式 +# 响应式列数 -`n-grid` 的 `cols` `x-gap` `y-gap`,`n-grid-item` 的 `span` `offset` 支持响应式参数配置。 +`n-grid` 的 `cols` `x-gap` `y-gap` 支持响应式参数配置。 `n-grid` 具有两种响应式模式,内部的 `n-grid-item` 遵从父级的模式。 @@ -8,6 +8,8 @@ `screen` 模式由浏览器视口的宽度控制响应式属性,有 `xs` `s` `m` `l` `xl` `2xl` 几个屏幕尺寸可供选择。一个响应式 `cols` 形如 `2 s:3 m:4 l:5 xl:6 2xl:7`。 +默认的屏幕配置为 `xs < 640 <= s < 1024 <= m < 1280 <= l < 1536 <= xl < 1920 <= xxl`。 + ```html Self 响应式 diff --git a/src/grid/src/Grid.tsx b/src/grid/src/Grid.tsx index 1736cd3ffa0..67ad82cab4e 100644 --- a/src/grid/src/Grid.tsx +++ b/src/grid/src/Grid.tsx @@ -10,9 +10,10 @@ import { mergeProps, ref, VNode, - Ref + Ref, + cloneVNode } from 'vue' -import { useBreakpoint, useMemo } from 'vooks' +import { useBreakpoints, useMemo } from 'vooks' import { VResizeObserver, VResizeObserverOnResize } from 'vueuc' import { pxfy, parseResponsivePropValue, beforeNextFrameOnce } from 'seemly' import { getSlot, flatten, ExtractPublicPropTypes } from '../../_utils' @@ -30,6 +31,7 @@ const gridProps = { type: [Number, String] as PropType, default: defaultCols }, + itemResponsive: Boolean, collapsed: Boolean, // may create grid rows < collapsedRows since a item may take all the row collapsedRows: { @@ -65,8 +67,9 @@ export default defineComponent({ const { mergedClsPrefixRef } = useConfig(props) const numRegex = /^\d+$/ const widthRef = ref(undefined) - const breakpointRef = useBreakpoint() + const breakpointsRef = useBreakpoints() const isResponsiveRef = useMemo(() => { + if (props.itemResponsive) return true if (!numRegex.test(props.cols.toString())) return true if (!numRegex.test(props.xGap.toString())) return true if (!numRegex.test(props.yGap.toString())) return true @@ -74,7 +77,7 @@ export default defineComponent({ }) const responsiveQueryRef = computed(() => { if (!isResponsiveRef.value) return undefined - return props.responsive === 'self' ? widthRef.value : breakpointRef.value + return props.responsive === 'self' ? widthRef.value : breakpointsRef.value }) const responsiveColsRef = useMemo(() => { return ( @@ -123,6 +126,7 @@ export default defineComponent({ rowGap: pxfy(responsiveYGapRef.value) } }), + isResponsive: isResponsiveRef, responsiveQuery: responsiveQueryRef, responsiveCols: responsiveColsRef, handleResize: handleResizeRef, @@ -135,12 +139,37 @@ export default defineComponent({ // render will be called twice when mounted, I can't figure out why // 2 jobs will be pushed into job queues with same id, and then be flushed - const children = flatten(getSlot(this)) + const rawChildren = flatten(getSlot(this)) + + const childrenAndRawSpan: Array<{ + child: VNode + rawChildSpan: number + }> = [] const { collapsed, collapsedRows, responsiveCols, responsiveQuery } = this + rawChildren.forEach((child) => { + if ((child?.type as any)?.__GRID_ITEM__ !== true) return + const clonedChild = cloneVNode(child) + + const rawChildSpan = Number( + parseResponsivePropValue( + clonedChild.props?.span as string | number | undefined, + responsiveQuery + ) ?? defaultSpan + ) + + if (rawChildSpan === 0) return + + childrenAndRawSpan.push({ + child: clonedChild, + rawChildSpan + }) + }) + let suffixSpan = 0 - const maybeSuffixNode = children[children.length - 1] + const maybeSuffixNode = + childrenAndRawSpan[childrenAndRawSpan.length - 1].child if (maybeSuffixNode?.props) { const suffixPropValue = maybeSuffixNode.props?.suffix if (suffixPropValue !== undefined && suffixPropValue !== false) { @@ -153,12 +182,11 @@ export default defineComponent({ let spanCounter = 0 let done = false - for (const child of children) { - // @ts-expect-error - if (child?.type?.__GRID_ITEM__ !== true) continue + for (const { child, rawChildSpan } of childrenAndRawSpan) { if (done) { this.overflow = true } + if (!done) { const childOffset = Number( parseResponsivePropValue( @@ -166,16 +194,9 @@ export default defineComponent({ responsiveQuery ) ?? 0 ) + const childSpan = - Math.min( - Number( - parseResponsivePropValue( - child.props?.span as string | number | undefined, - responsiveQuery - ) ?? defaultSpan - ) + childOffset, - responsiveCols - ) || 1 + Math.min(rawChildSpan + childOffset, responsiveCols) || 1 if (!child.props) { child.props = { @@ -223,10 +244,10 @@ export default defineComponent({ }, this.$attrs ), - children + childrenAndRawSpan.map(({ child }) => child) ) } - return this.responsive === 'self' ? ( + return this.isResponsive && this.responsive === 'self' ? ( {{ default: renderContent