浏览代码

fix: collaspe 数据更新问题处理 (#1401)

* fix: countup优化滚动逻辑

* fix: collapse 无法动态更新问题修复

* fix: 解决H5侧动态加载问题

* docs: 文档增加调试功能(Barrage、Signature、CountUp、TextArea、Collapse)

* feat: 折叠面板 collapse 单元测试

* feat: countUp 单元测试

* feat: barrage 单元测试

* fix: 签名组件单元测试

* feat: textarea 单元测试

* feat: collapse 标题多行展示,无内容不下拉,图标位置配置

* feat: textarea 自动撑开,collapse 组件能力

* fix: collapse 单元测试优化

* fix: textarea 单元测试优化

* fix: 修改input参数,maxNum 改为 maxLength,文档修改等

* fix: maxlength 值

* fix: textarea 自适应

* fix: textarea rows

* upd: notify 增加组件调用方式

* fix: demo 修改

* feat: 新增collapse组件自定义内容(不折叠)功能

* fix: notify 单元测试优化

* feat: searchbar 组件能力补充

* feat: collapse,layout 组件国际化

* upd: countup、barrage、signature、Skeleton组件国际化

* fix: demo及文档修改,组件优化

* feat: textarea 增加autofocus、disabled等属性,增加点击区域事件

* fix: 解决 flexwrap 问题

* fix: 文档修改

* fix: 优化

* fix: collaspe 数据更新支持外部调用

* fix: demo

Co-authored-by: richard1015 <51844712@qq.com>
Ymm 3 年之前
父节点
当前提交
6b63084ad6

+ 77 - 0
project.config.json

@@ -0,0 +1,77 @@
+{
+  "description": "项目配置文件",
+  "packOptions": {
+    "ignore": []
+  },
+  "setting": {
+    "urlCheck": true,
+    "es6": true,
+    "enhance": true,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": false,
+    "coverView": true,
+    "nodeModules": false,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": false,
+    "checkInvalidKey": true,
+    "checkSiteMap": true,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "useMultiFrameRuntime": true,
+    "useApiHook": true,
+    "useApiHostProcess": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "useIsolateContext": true,
+    "userConfirmedBundleSwitch": false,
+    "packNpmManually": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "disableUseStrict": false,
+    "minifyWXML": true,
+    "showES6CompileOption": false,
+    "useCompilerPlugins": false,
+    "ignoreUploadUnusedFiles": true
+  },
+  "compileType": "miniprogram",
+  "libVersion": "2.24.4",
+  "appid": "wx9ac45039b7813c7d",
+  "projectname": "nutui",
+  "debugOptions": {
+    "hidedInDevtools": []
+  },
+  "scripts": {},
+  "staticServerOptions": {
+    "baseURL": "",
+    "servePath": ""
+  },
+  "isGameTourist": false,
+  "condition": {
+    "search": {
+      "list": []
+    },
+    "conversation": {
+      "list": []
+    },
+    "game": {
+      "list": []
+    },
+    "plugin": {
+      "list": []
+    },
+    "gamePlugin": {
+      "list": []
+    },
+    "miniprogram": {
+      "list": []
+    }
+  }
+}

+ 6 - 2
src/packages/__VUE/addresslist/index.taro.vue

@@ -65,7 +65,7 @@
   </div>
 </template>
 <script lang="ts">
-import {toRefs, reactive, onMounted, ref, watch} from 'vue';
+import { toRefs, reactive, onMounted, ref, watch } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create, translate } = createComponent('addresslist');
 import LongPressShell from './components/LongPressShell.vue';
@@ -130,7 +130,11 @@ export default create({
     };
 
     // 监听props.data的变更重新渲染列表
-    watch(() => props.data, () => trowelData(), {deep:true});
+    watch(
+      () => props.data,
+      () => trowelData(),
+      { deep: true }
+    );
 
     const clickDelIcon = (event, item) => {
       emit('handelDelIcon', event, item);

+ 40 - 2
src/packages/__VUE/collapse/index.taro.vue

@@ -1,11 +1,12 @@
 <template>
-  <view>
+  <view ref="collapseDom">
     <slot></slot>
   </view>
 </template>
 <script lang="ts">
-import { provide } from 'vue';
+import { onMounted, provide, ref, watch, getCurrentInstance } from 'vue';
 import { createComponent } from '@/packages/utils/create';
+import { nextTick } from '@tarojs/taro';
 const { create } = createComponent('collapse');
 export default create({
   props: {
@@ -54,6 +55,8 @@ export default create({
   },
   emits: ['update:active', 'change'],
   setup(props, { emit, slots }) {
+    const collapseDom: any = ref(null);
+
     const changeVal = (val: string | number | Array<string | number>) => {
       emit('update:active', val);
       emit('change', val);
@@ -62,6 +65,7 @@ export default create({
     const changeValAry = (name: string) => {
       const activeItem: any = props.active instanceof Object ? Object.values(props.active) : props.active;
       let index = -1;
+
       activeItem.forEach((item: string | number, idx: number) => {
         if (String(item) == String(name)) {
           index = idx;
@@ -97,6 +101,39 @@ export default create({
       });
       return act;
     };
+    const childrenDom = ref(null);
+    onMounted(() => {
+      childrenDom.value = (getCurrentInstance() as any).provides.collapseParent.children;
+    });
+
+    watch(
+      () => props.active,
+      (newval: any, oldval) => {
+        nextTick(() => {
+          let domsProps: any = slots?.default?.();
+          let doms: any = childrenDom.value;
+          Array.from(doms).forEach((item: any, index: number) => {
+            if (typeof newval == 'number' || typeof newval == 'string') {
+              if (newval == domsProps[index].props.name) {
+                item.changeOpen(true);
+              } else {
+                item.changeOpen(false);
+              }
+            } else if (Object.values(newval) instanceof Array) {
+              if (
+                newval.indexOf(Number(domsProps[index].props.name)) > -1 ||
+                newval.indexOf(String(domsProps[index].props.name)) > -1
+              ) {
+                item.changeOpen(true);
+              } else {
+                item.changeOpen(false);
+              }
+            }
+            item.animation();
+          });
+        });
+      }
+    );
 
     const getParentChildren = () => {
       return slots.default?.();
@@ -110,6 +147,7 @@ export default create({
       activeIndex,
       getParentChildren
     });
+    return { collapseDom };
   }
 });
 </script>

+ 34 - 3
src/packages/__VUE/collapse/index.vue

@@ -1,10 +1,10 @@
 <template>
-  <view>
+  <view ref="collapseDom">
     <slot></slot>
   </view>
 </template>
 <script lang="ts">
-import { provide } from 'vue';
+import { provide, ref, watch } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { create } = createComponent('collapse');
 export default create({
@@ -53,7 +53,36 @@ export default create({
     }
   },
   emits: ['update:active', 'change'],
-  setup(props, { emit }) {
+  setup(props, { emit, slots }) {
+    const collapseDom: any = ref(null);
+    watch(
+      () => props.active,
+      (newval: any, oldval) => {
+        let domsProps: any = slots?.default?.();
+        let doms: any = collapseDom.value?.children;
+        Array.from(doms).forEach((dom: any, index: number) => {
+          const item = dom['__vueParentComponent']['ctx'];
+          if (typeof newval == 'number' || typeof newval == 'string') {
+            if (newval == domsProps[index].props.name) {
+              item.changeOpen(!item.openExpanded);
+            } else {
+              item.changeOpen(false);
+            }
+          } else if (Object.values(newval) instanceof Array) {
+            if (
+              newval.indexOf(Number(domsProps[index].props.name)) > -1 ||
+              newval.indexOf(String(domsProps[index].props.name)) > -1
+            ) {
+              item.changeOpen(true);
+            } else {
+              item.changeOpen(false);
+            }
+          }
+          item.animation();
+        });
+      }
+    );
+
     const changeVal = (val: string | number | Array<string | number>) => {
       emit('update:active', val);
       emit('change', val);
@@ -85,6 +114,8 @@ export default create({
       changeVal,
       isExpanded
     });
+
+    return { collapseDom };
   }
 });
 </script>

+ 22 - 10
src/packages/__VUE/collapseitem/index.taro.vue

@@ -117,7 +117,7 @@ export default create({
       icon: parent.props.icon,
       iconSize: parent.props.iconSize,
       iconColor: parent.props.iconColor,
-      openExpanded: null,
+      openExpanded: false,
       // classDirection: 'right',
       iconStyle: {
         transform: 'rotate(0deg)',
@@ -188,19 +188,31 @@ export default create({
 
     const currentName = computed(() => props.name);
     const toggleOpen = () => {
+      // if (parent.props.accordion) {
+      //   parent.children.forEach((item: any, index: number) => {
+      //     if (currentName.value == item.name) {
+      //       item.changeOpen(!item.openExpanded);
+      //     } else {
+      //       item.changeOpen(false);
+      //       item.animation();
+      //     }
+      //   });
+      //   nextTick(() => {
+      //     parent.changeVal(currentName.value);
+      //     animation();
+      //   });
+      // } else {
+      //   parent.changeValAry(props.name);
+      //   open();
+      // }
       if (parent.props.accordion) {
-        parent.children.forEach((item: any, index: number) => {
-          if (currentName.value == item.name) {
-            item.changeOpen(!item.openExpanded);
+        nextTick(() => {
+          if (currentName.value == parent.props.active) {
+            open();
           } else {
-            item.changeOpen(false);
-            item.animation();
+            parent.changeVal(currentName.value);
           }
         });
-        nextTick(() => {
-          parent.changeVal(currentName.value);
-          animation();
-        });
       } else {
         parent.changeValAry(props.name);
         open();

+ 19 - 11
src/packages/__VUE/collapseitem/index.vue

@@ -179,20 +179,25 @@ export default create({
     const currentName = computed(() => props.name);
     const toggleOpen = () => {
       if (parent.props.accordion) {
-        parent.children.forEach((item: any, index: number) => {
-          if (currentName.value == item.name) {
-            item.changeOpen(!item.openExpanded);
+        // parent.children.forEach((item: any, index: number) => {
+        //   if (currentName.value == item.name) {
+        //     item.changeOpen(!item.openExpanded);
+        //   } else {
+        //     item.changeOpen(false);
+        //     item.animation();
+        //   }
+        // });
+        nextTick(() => {
+          if (currentName.value == parent.props.active) {
+            open();
           } else {
-            item.changeOpen(false);
-            item.animation();
+            parent.changeVal(currentName.value);
           }
-        });
-        nextTick(() => {
-          parent.changeVal(currentName.value);
-          animation();
+          // parent.changeVal(currentName.value);
+          // animation();
         });
       } else {
-        parent.changeValAry(props.name);
+        parent.changeValAry(String(props.name));
         open();
       }
     };
@@ -223,7 +228,7 @@ export default create({
       }
     );
 
-    onMounted(() => {
+    const init = () => {
       const { name } = props;
       const active = parent && parent.props.active;
       nextTick(() => {
@@ -238,6 +243,9 @@ export default create({
           }
         }
       });
+    };
+    onMounted(() => {
+      init();
       // proxyData.classDirection = parent.props.expandIconPosition;
       // if (parent.props.icon && parent.props.icon != 'none') {
       //   proxyData.iconStyle['background-image'] =

+ 1 - 0
src/packages/__VUE/searchbar/doc.en-US.md

@@ -196,6 +196,7 @@ app.use(SearchBar).use(Icon);
 |placeholder | input box default dark grain | string | 'please enter'|
 |clear | whether to display the clear button | Boolean | true|
 |background | input box external background | string | '#fff'|
+|confirm-type | the text of the button at the bottom right corner of the keyboard (` only applet supported ') takes effect only when' type='text ''. The optional values `send`: send, `search`: search, `next`: next, `go`: go, `done`: finish | string | `done`|
 |input-background | internal background of input box | string | '#f7f7f7'|
 |autofocus `v3.1.21` | Auto focus | boolean | false |
 |disabled `v3.1.21`| disable input box | Boolean | false|

+ 0 - 1
src/packages/__VUE/searchbar/doc.md

@@ -197,7 +197,6 @@ app.use(SearchBar).use(Icon);
 | clearable          | 是否展示清除按钮 | Boolean | true     |
 | background      | 输入框外部背景 | String |   '#fff'   |
 | input-background   | 输入框内部背景 | String |   '#f7f7f7'   |
-| input-background   | 输入框内部背景 | String |   '#f7f7f7'   |
 | confirm-type   | 键盘右下角按钮的文字(`仅支持小程序`),仅在`type='text'`时生效,可选值 `send`:发送、`search`:搜索、`next`:下一个、`go`:前往、`done`:完成 | String |   `done`   |
 | input-background   | 输入框内部背景 | String |   '#f7f7f7'   |
 | autofocus `v3.1.21` | 是否自动聚焦 | boolean | false |

+ 1 - 1
src/packages/__VUE/searchbar/index.taro.vue

@@ -49,7 +49,7 @@ interface Events {
   eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:modelValue';
   params: (string | number | Event)[];
 }
-export type confirmTextType = 'send' | 'search' | 'next' | 'go' | 'done'
+export type confirmTextType = 'send' | 'search' | 'next' | 'go' | 'done';
 
 export default create({
   props: {

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

@@ -78,7 +78,7 @@ export default {
 |v-model | input value, support two-way binding | string | -|
 |placeholder | set placeholder prompt text | string | ` 'please enter content' `|
 |max-length | limit the maximum input characters | string, number | -|
-|rows | height of textarea, with priority higher than autosize attribute | string and number | ` 2 `|
+|rows | height of textarea, with priority higher than autosize attribute `Only H5 is supported`| string and number | ` 2 `|
 |limit-show | whether textarea displays the input characters. Use | Boolean | ` false` |
 |autosize | whether to adapt the content height. You can also pass in objects, such as {maxheight: 200, minheight: 100}. The unit is PX | Boolean, {maxheight?: number; minheight?: number} | ` false `|
 |text-align | text position, optional values ` left ,  center,  right `| string |  `left`|

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

@@ -78,7 +78,7 @@ export default {
 | v-model     | 输入值,支持双向绑定                             | String         | -              |
 | placeholder | 设置占位提示文字                                 | String         | `'请输入内容'` |
 | max-length  | 限制最长输入字符                                 | String、Number | -              |
-| rows        `v3.1.20`| textarea的高度,优先级高于autosize属性                                   | String、Number | `2`            |
+| rows        `v3.1.20`| textarea的高度,优先级高于autosize属性  `仅支持 H5`                                 | String、Number | `2`            |
 | limit-show  | textarea是否展示输入字符。须配合`max-length`使用 | Boolean        | `false`        |
 | autosize    `v3.1.20`| 是否自适应内容高度,也可传入对象, 如 { maxHeight: 200, minHeight: 100 },单位为px | Boolean 、{maxHeight?: number; minHeight?: number}       | `false`        |
 | text-align  | 文本位置,可选值`left`,`center`,`right`           | String         | `left`         |

+ 34 - 11
src/packages/__VUE/textarea/index.taro.vue

@@ -1,4 +1,4 @@
-onMounted, nextTick, , watch, ref<template>
+<template>
   <view :class="classes">
     <view v-if="readonly" class="nut-textarea__textarea">
       {{ modelValue }}
@@ -25,7 +25,7 @@ onMounted, nextTick, , watch, ref<template>
 <script lang="ts">
 import { computed, nextTick, onMounted, ref, watch } from 'vue';
 import { createComponent } from '@/packages/utils/create';
-
+import Taro, { eventCenter, getCurrentInstance as getCurrentInstanceTaro } from '@tarojs/taro';
 const { componentName, create, translate } = createComponent('textarea');
 
 export default create({
@@ -63,7 +63,7 @@ export default create({
       default: false
     },
     autosize: {
-      type: Boolean,
+      type: [Boolean, Object],
       default: false
     },
     autofocus: {
@@ -85,7 +85,8 @@ export default create({
 
     const styles: any = computed(() => {
       return {
-        textAlign: props.textAlign
+        textAlign: props.textAlign,
+        height: props.autosize ? heightSet.value : 'null'
         // resize: props.autosize ? 'vertical' : 'none'
       };
     });
@@ -120,12 +121,15 @@ export default create({
       emit('blur', event);
     };
 
-    const textareaRef = ref();
-
+    const textareaRef = ref<any>(null);
+    const textareaHeight = ref();
+    const heightSet = ref('auto');
     const getContentHeight = () => {
-      let textarea = textareaRef.value;
-      textarea.style.height = 'auto';
-      let height = textarea.scrollHeight;
+      heightSet.value = 'auto';
+      let height = textareaHeight.value;
+      // 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) {
@@ -136,7 +140,8 @@ export default create({
         }
       }
       if (height) {
-        textarea.style.height = height + 'px';
+        // textarea.style.height = height + 'px';
+        heightSet.value = height + 'px';
       }
     };
     watch(
@@ -148,9 +153,27 @@ export default create({
       }
     );
 
+    const getRefHeight = () => {
+      const query = Taro.createSelectorQuery();
+      // const query = Taro.createSelectorQuery();
+      query.selectAll('.nut-textarea__textarea').boundingClientRect();
+      let uid = textareaRef.value ? textareaRef.value.uid : '0';
+      query.exec((res) => {
+        if (res[0] && textareaRef.value) {
+          let _item: any = Array.from(res[0]).filter((item: any) => item.id == uid);
+          textareaHeight.value = _item[0]['height'] || 30;
+        }
+      });
+    };
+
     onMounted(() => {
       if (props.autosize) {
-        nextTick(getContentHeight);
+        eventCenter.once((getCurrentInstanceTaro() as any).router.onReady, () => {
+          getRefHeight();
+        });
+        setTimeout(() => {
+          nextTick(getContentHeight);
+        }, 300);
       }
     });
 

+ 4 - 6
src/sites/mobile-taro/vue/project.config.json

@@ -30,7 +30,6 @@
       "disablePlugins": [],
       "outputPath": ""
     },
-    "enableEngineNative": false,
     "useIsolateContext": false,
     "userConfirmedBundleSwitch": false,
     "packNpmManually": false,
@@ -40,16 +39,12 @@
     "minifyWXML": true,
     "showES6CompileOption": false,
     "useCompilerPlugins": false,
-    "ignoreUploadUnusedFiles": true,
-    "useStaticServer": true
+    "ignoreUploadUnusedFiles": true
   },
   "compileType": "miniprogram",
   "simulatorType": "wechat",
   "simulatorPluginLibVersion": {},
   "libVersion": "2.17.3",
-  "condition": {
-    "miniprogram": {}
-  },
   "srcMiniprogramRoot": "dist/",
   "packOptions": {
     "ignore": [],
@@ -58,5 +53,8 @@
   "editorSetting": {
     "tabIndent": "insertSpaces",
     "tabSize": 2
+  },
+  "condition": {
+    "miniprogram": {}
   }
 }

+ 18 - 7
src/sites/mobile-taro/vue/project.private.config.json

@@ -1,6 +1,16 @@
 {
   "setting": {},
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
   "condition": {
+    "plugin": {
+      "list": []
+    },
+    "game": {
+      "list": []
+    },
+    "gamePlugin": {
+      "list": []
+    },
     "miniprogram": {
       "list": [
         {
@@ -35,19 +45,20 @@
           "scene": null
         },
         {
-          "name": "feedback/pages/swiper/index",
-          "pathName": "feedback/pages/swiper/index",
+          "name": "exhibition/pages/collapse/index",
+          "pathName": "exhibition/pages/collapse/index",
           "query": "",
-          "scene": null
+          "scene": null,
+          "launchMode": "default"
         },
         {
-          "name": "dentry/pages/input/index",
-          "pathName": "dentry/pages/input/index",
+          "name": "dentry/pages/textarea/index",
+          "pathName": "dentry/pages/textarea/index",
           "query": "",
+          "launchMode": "default",
           "scene": null
         }
       ]
     }
-  },
-  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html"
+  }
 }

+ 1 - 1
src/sites/mobile-taro/vue/src/dentry/pages/searchbar/index.vue

@@ -56,7 +56,7 @@ export default {
       searchValue3: '',
       searchValue4: '',
       searchValue5: '',
-      confirmType: 'search',
+      confirmType: 'search'
     });
 
     const search = function (e: any) {

+ 1 - 1
src/sites/mobile-taro/vue/src/dentry/pages/textarea/index.vue

@@ -5,7 +5,7 @@
     <h2>显示字数统计</h2>
     <nut-textarea v-model="value2" limit-show max-length="20" />
     <h2>高度自定义,拉伸</h2>
-    <nut-textarea v-model="value3" rows="10" autosize />
+    <nut-textarea v-model="value3" autosize />
     <h2>只读状态</h2>
     <nut-textarea readonly model-value="textarea只读状态" />
     <h2>禁用</h2>

+ 77 - 0
src/sites/mobile-taro/vue/src/project.config.json

@@ -0,0 +1,77 @@
+{
+  "description": "项目配置文件",
+  "packOptions": {
+    "ignore": []
+  },
+  "setting": {
+    "urlCheck": true,
+    "es6": true,
+    "enhance": true,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": false,
+    "coverView": true,
+    "nodeModules": false,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": false,
+    "checkInvalidKey": true,
+    "checkSiteMap": true,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "useMultiFrameRuntime": true,
+    "useApiHook": true,
+    "useApiHostProcess": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "useIsolateContext": true,
+    "userConfirmedBundleSwitch": false,
+    "packNpmManually": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "disableUseStrict": false,
+    "minifyWXML": true,
+    "showES6CompileOption": false,
+    "useCompilerPlugins": false,
+    "ignoreUploadUnusedFiles": true
+  },
+  "compileType": "miniprogram",
+  "libVersion": "2.24.4",
+  "appid": "wx9ac45039b7813c7d",
+  "projectname": "src",
+  "debugOptions": {
+    "hidedInDevtools": []
+  },
+  "scripts": {},
+  "staticServerOptions": {
+    "baseURL": "",
+    "servePath": ""
+  },
+  "isGameTourist": false,
+  "condition": {
+    "search": {
+      "list": []
+    },
+    "conversation": {
+      "list": []
+    },
+    "game": {
+      "list": []
+    },
+    "plugin": {
+      "list": []
+    },
+    "gamePlugin": {
+      "list": []
+    },
+    "miniprogram": {
+      "list": []
+    }
+  }
+}