浏览代码

feat: collapse 标题多行展示,无内容不下拉,图标位置配置,textarea 自动撑开,collapse 组件能力 (#1121)

* feat: textarea 自动撑开,collapse 组件能力
Ymm0008 3 年之前
父节点
当前提交
a8b0ff4e22

+ 1 - 1
src/packages/__VUE/collapse/demo.vue

@@ -45,7 +45,7 @@
       title-icon="issue"
       title-icon-color="red"
       title-icon-size="20px"
-      title-icon-position="left"
+      title-icon-position="right"
       icon="down-arrow"
       :accordion="true"
     >

+ 2 - 0
src/packages/__VUE/collapse/doc.md

@@ -236,6 +236,7 @@ export default {
 | title-icon-position | 标题图标位置 | string | ‘left' |
 | rotate | 点击折叠和展开的旋转角度,在自定义图标模式下生效 | string \ number | 180 |
 
+
 ### CollapseItem Prop
 | 参数 | 说明 | 类型 | 默认值 | 
 |------|------|------|------|
@@ -244,6 +245,7 @@ export default {
 | sub-title | 标题栏副标题,支持插槽传入(props传入的优先级更高) | string | - |
 | disabled | 标题栏是否禁用 | boolean | false |
 
+
 ### Events
 
 | 事件名 | 说明 | 回调参数 |

+ 6 - 0
src/packages/__VUE/collapseitem/index.scss

@@ -65,6 +65,9 @@
       margin: 0px 10px 0 0;
     }
   }
+  // .extraRender {
+  //   display: block;
+  // }
   .collapse-wrapper {
     display: block;
     position: relative;
@@ -79,6 +82,9 @@
       line-height: $collapse-wrapper-content-line-height;
       background-color: $collapse-wrapper-content-background-color;
     }
+    .empty {
+      padding: $collapse-wrapper-empty-content-padding;
+    }
   }
   .open-style {
     will-change: height;

+ 0 - 12
src/packages/__VUE/collapseitem/index.taro.vue

@@ -20,21 +20,9 @@
             <template v-else>
               <view v-html="title" class="collapse-icon-title"></view>
             </template>
-            <!-- <view
-              v-html="title"
-              class="collapse-icon-title"
-              v-if="title"
-            ></view>
-            <mTitle v-else>
-              <slot name="mTitle"></slot>
-            </mTitle> -->
           </view>
         </view>
       </view>
-      <!-- <view v-if="subTitle" v-html="subTitle" class="subTitle"></view>
-      <view class="subTitle" v-else>
-        <slot name="sTitle"></slot>
-      </view> -->
       <view v-if="$slots.sTitle" class="subTitle">
         <slot name="sTitle"></slot>
       </view>

+ 22 - 13
src/packages/__VUE/collapseitem/index.vue

@@ -35,7 +35,7 @@
       ></nut-icon>
     </view>
     <view class="collapse-wrapper" ref="wrapperRef">
-      <view class="collapse-content" ref="contentRef">
+      <view :class="['collapse-content', emptyContent]" ref="contentRef">
         <slot></slot>
       </view>
     </view>
@@ -91,6 +91,7 @@ export default create({
         [`${prefixCls}-icon`]: parent.props.icon
       };
     });
+
     const relation = (child: ComponentInternalInstance): void => {
       if (child.proxy) {
         parent.children.push(child.proxy);
@@ -220,18 +221,18 @@ export default create({
     onMounted(() => {
       const { name } = props;
       const active = parent && parent.props.active;
-
-      if (typeof active == 'number' || typeof active == 'string') {
-        if (name == active) {
-          defaultOpen();
-        }
-      } else if (Object.values(active) instanceof Array) {
-        const f = Object.values(active).filter((item) => item == name);
-        if (f.length > 0) {
-          defaultOpen();
+      nextTick(() => {
+        if (typeof active == 'number' || typeof active == 'string') {
+          if (name == active) {
+            defaultOpen();
+          }
+        } else if (Object.values(active) instanceof Array) {
+          const f = Object.values(active).filter((item) => item == name);
+          if (f.length > 0) {
+            defaultOpen();
+          }
         }
-      }
-
+      });
       // proxyData.classDirection = parent.props.expandIconPosition;
       // if (parent.props.icon && parent.props.icon != 'none') {
       //   proxyData.iconStyle['background-image'] =
@@ -244,9 +245,17 @@ export default create({
       //   proxyData.iconStyle['height'] = parent.props.iconHeight;
       // }
     });
-
+    const emptyContent = computed(() => {
+      let ele = contentRef.value;
+      let _class = '';
+      if (!ele?.innerText) {
+        _class = 'empty';
+      }
+      return _class;
+    });
     return {
       classes,
+      emptyContent,
       ...toRefs(proxyData),
       ...toRefs(parent.props),
       ...toRefs(titleIconStyle),

+ 6 - 6
src/packages/__VUE/textarea/demo.vue

@@ -1,17 +1,17 @@
 <template>
   <div class="demo full">
-    <h2>基础用法</h2>
-    <nut-textarea v-model="value" />
+    <!-- <h2>基础用法</h2> -->
+    <!-- <nut-textarea v-model="value" />
     <h2>显示字数统计</h2>
-    <nut-textarea v-model="value2" limit-show max-length="20" />
+    <nut-textarea v-model="value2" limit-show max-length="20" /> -->
     <h2>高度自定义,拉伸</h2>
-    <nut-textarea v-model="value3" rows="10" autosize />
-    <h2>只读</h2>
+    <nut-textarea v-model="value3" autosize />
+    <!-- <h2>只读</h2>
     <nut-textarea readonly model-value="textarea只读状态" />
     <h2>禁用</h2>
     <nut-textarea disabled model-value="textarea禁用状态" limit-show max-length="20" />
     <h2>自动获取焦点</h2>
-    <nut-textarea autofocus v-model="value4" />
+    <nut-textarea autofocus v-model="value4" /> -->
   </div>
 </template>
 

+ 1 - 1
src/packages/__VUE/textarea/doc.md

@@ -80,7 +80,7 @@ export default {
 | max-length  | 限制最长输入字符                                 | String、Number | -              |
 | rows        | textarea的高度                                   | String、Number | `2`            |
 | limit-show  | textarea是否展示输入字符。须配合`max-length`使用 | Boolean        | `false`        |
-| autosize    | 高度是否可拉伸                                   | Boolean        | `false`        |
+| autosize    | 是否自适应内容高度,也可传入对象, 如 { maxHeight: 200, minHeight: 100 },单位为px | Boolean 、{maxHeight?: number; minHeight?: number}       | `false`        |
 | text-align  | 文本位置,可选值`left`,`center`,`right`           | String         | `left`         |
 | readonly    | 只读属性                                         | Boolean        | `false`        |
 | disabled    | 禁用属性                                         | Boolean        | `false`        |

+ 41 - 5
src/packages/__VUE/textarea/index.taro.vue

@@ -1,10 +1,11 @@
-<template>
+onMounted, nextTick, , watch, ref<template>
   <view :class="classes">
     <view v-if="readonly" class="nut-textarea__textarea">
       {{ modelValue }}
     </view>
     <textarea
       v-else
+      ref="textareaRef"
       class="nut-textarea__textarea"
       :style="styles"
       :rows="rows"
@@ -22,7 +23,7 @@
   </view>
 </template>
 <script lang="ts">
-import { computed } from 'vue';
+import { computed, nextTick, onMounted, ref, watch } from 'vue';
 import { createComponent } from '../../utils/create';
 
 const { componentName, create } = createComponent('textarea');
@@ -82,10 +83,10 @@ export default create({
       };
     });
 
-    const styles = computed(() => {
+    const styles: any = computed(() => {
       return {
-        textAlign: props.textAlign,
-        resize: props.autosize ? 'vertical' : 'none'
+        textAlign: props.textAlign
+        // resize: props.autosize ? 'vertical' : 'none'
       };
     });
 
@@ -119,7 +120,42 @@ export default create({
       emit('blur', event);
     };
 
+    const textareaRef = ref();
+
+    const getContentHeight = () => {
+      let textarea = textareaRef.value;
+      textarea.style.height = 'auto';
+      let height = textarea.scrollHeight;
+      if (typeof props.autosize === 'object') {
+        const { maxHeight, minHeight } = props.autosize;
+        if (maxHeight !== undefined) {
+          height = Math.min(height, maxHeight);
+        }
+        if (minHeight !== undefined) {
+          height = Math.max(height, minHeight);
+        }
+      }
+      if (height) {
+        textarea.style.height = height + 'px';
+      }
+    };
+    watch(
+      () => props.modelValue,
+      () => {
+        if (props.autosize) {
+          nextTick(getContentHeight);
+        }
+      }
+    );
+
+    onMounted(() => {
+      if (props.autosize) {
+        nextTick(getContentHeight);
+      }
+    });
+
     return {
+      textareaRef,
       classes,
       styles,
       change,

+ 38 - 5
src/packages/__VUE/textarea/index.vue

@@ -1,6 +1,7 @@
-<template>
+, nextTick<template>
   <view :class="classes">
     <textarea
+      ref="textareaRef"
       class="nut-textarea__textarea"
       :style="styles"
       :rows="rows"
@@ -18,7 +19,7 @@
   </view>
 </template>
 <script lang="ts">
-import { computed, onMounted } from 'vue';
+import { watch, ref, computed, onMounted, nextTick } from 'vue';
 import { createComponent } from '../../utils/create';
 
 const { componentName, create } = createComponent('textarea');
@@ -70,6 +71,7 @@ export default create({
   emits: ['update:modelValue', 'change', 'blur', 'focus'],
 
   setup(props, { emit }) {
+    const textareaRef = ref();
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
@@ -82,15 +84,45 @@ export default create({
       if (props.modelValue) {
         emitChange(String(props.modelValue));
       }
+      if (props.autosize) {
+        nextTick(getContentHeight);
+      }
     });
 
-    const styles = computed(() => {
+    const styles: any = computed(() => {
       return {
-        textAlign: props.textAlign,
-        resize: props.autosize ? 'vertical' : 'none'
+        textAlign: props.textAlign
+        // resize: props.autosize ? 'vertical' : 'none'
       };
     });
 
+    const getContentHeight = () => {
+      let textarea = textareaRef.value;
+      textarea.style.height = 'auto';
+      let height = textarea.scrollHeight;
+      if (typeof props.autosize === 'object') {
+        const { maxHeight, minHeight } = props.autosize;
+        if (maxHeight !== undefined) {
+          height = Math.min(height, maxHeight);
+        }
+        if (minHeight !== undefined) {
+          height = Math.max(height, minHeight);
+        }
+      }
+      if (height) {
+        textarea.style.height = height + 'px';
+      }
+    };
+
+    watch(
+      () => props.modelValue,
+      () => {
+        if (props.autosize) {
+          nextTick(getContentHeight);
+        }
+      }
+    );
+
     const emitChange = (value: string, event?: Event) => {
       if (props.maxLength && value.length > Number(props.maxLength)) {
         value = value.substring(0, Number(props.maxLength));
@@ -122,6 +154,7 @@ export default create({
     };
 
     return {
+      textareaRef,
       classes,
       styles,
       change,

+ 2 - 1
src/packages/styles/variables-jdt.scss

@@ -549,7 +549,7 @@ $menu-item-option-i-margin-right: 6px !default;
 $menu-bar-box-shadow: 0 2px 12px rgba(89, 89, 89, 0.12) !default;
 
 // collapse
-$collapse-item-padding: 13px 26px !default;
+$collapse-item-padding: 13px 36px 13px 26px !default;
 $collapse-item-color: rgba(0, 0, 0, 0.85) !default;
 $collapse-item-disabled-color: #bfbfbf !default;
 $collapse-item-icon-color: #666666 !default;
@@ -557,6 +557,7 @@ $collapse-item-font-size: $font-size-2 !default;
 $collapse-item-line-height: 24px !default;
 $collapse-item-sub-title-color: #666666 !default;
 $collapse-wrapper-content-padding: 12px 26px !default;
+$collapse-wrapper-empty-content-padding: 0 26px !default;
 $collapse-wrapper-content-color: #8c8c8c !default;
 $collapse-wrapper-content-font-size: $font-size-2 !default;
 $collapse-wrapper-content-line-height: 1.5 !default;

+ 2 - 1
src/packages/styles/variables.scss

@@ -574,7 +574,7 @@ $menu-item-option-i-margin-right: 6px !default;
 $menu-bar-box-shadow: 0 2px 12px rgba(89, 89, 89, 0.12) !default;
 
 // collapse
-$collapse-item-padding: 13px 26px !default;
+$collapse-item-padding: 13px 36px 13px 26px !default;
 $collapse-item-color: #666666 !default;
 $collapse-item-disabled-color: #c8c9cc !default;
 $collapse-item-icon-color: #666666 !default;
@@ -582,6 +582,7 @@ $collapse-item-font-size: $font-size-2 !default;
 $collapse-item-line-height: 24px !default;
 $collapse-item-sub-title-color: #666666 !default;
 $collapse-wrapper-content-padding: 12px 26px !default;
+$collapse-wrapper-empty-content-padding: 0 26px !default;
 $collapse-wrapper-content-color: #666666 !default;
 $collapse-wrapper-content-font-size: $font-size-2 !default;
 $collapse-wrapper-content-line-height: 1.5 !default;