Browse Source

Merge branch 'next' of https://github.com/jdf2e/nutui into next

richard1015 3 years ago
parent
commit
f68edeaf05

+ 5 - 1
src/packages/__VUE/address/index.scss

@@ -140,7 +140,7 @@
         .region-item {
           display: flex;
           align-items: center;
-          margin-bottom: 20px;
+
           font-size: $address-region-item-font-size;
           color: $address-region-item-color;
           &.active {
@@ -151,6 +151,10 @@
             margin-right: 6px;
             color: $address-icon-color !important;
           }
+
+          > div {
+            margin: 10px 0;
+          }
         }
       }
     }

+ 11 - 10
src/packages/__VUE/address/index.taro.vue

@@ -54,15 +54,17 @@
               :class="['region-item', selectedRegion[tabName[tabIndex]].id == item.id ? 'active' : '']"
               @click="nextAreaList(item)"
             >
-              <nut-icon
-                class="region-item-icon"
-                type="self"
-                v-bind="$attrs"
-                :name="selectedIcon"
-                size="13px"
-                v-if="selectedRegion[tabName[tabIndex]].id == item.id"
-              ></nut-icon
-              >{{ item.name }}
+              <div>
+                <nut-icon
+                  class="region-item-icon"
+                  type="self"
+                  v-bind="$attrs"
+                  :name="selectedIcon"
+                  size="13px"
+                  v-if="selectedRegion[tabName[tabIndex]].id == item.id"
+                ></nut-icon
+                >{{ item.name }}
+              </div>
             </li>
           </ul>
         </view>
@@ -136,7 +138,6 @@
 import { reactive, ref, toRefs, watch, computed, onMounted } from 'vue';
 import { popupProps } from '../popup/index.taro.vue';
 import { createComponent } from '@/packages/utils/create';
-import Taro from '@tarojs/taro';
 
 const { create, componentName, translate } = createComponent('address');
 

+ 4 - 0
src/packages/__VUE/ellipsis/index.scss

@@ -5,6 +5,10 @@
     color: $ellipsis-expand-collapse-color;
     display: inline;
   }
+
+  .nut-ellipsis-wordbreak {
+    word-break: break-all;
+  }
 }
 
 .nut-ellipsis-copy {

+ 114 - 94
src/packages/__VUE/ellipsis/index.taro.vue

@@ -1,12 +1,12 @@
 <template>
   <view>
     <view :class="classes" @click="handleClick" ref="root" :id="'root' + refRandomId">
-      <view v-if="!exceeded">{{ content }}</view>
+      <view class="nut-ellipsis-wordbreak" v-if="!exceeded">{{ content }}</view>
 
-      <view v-if="exceeded && !expanded">
-        {{ ellipsis.leading
+      <view v-if="exceeded && !expanded" class="nut-ellipsis-wordbreak">
+        {{ ellipsis.leading }}{{ ellipsis.leading && symbol
         }}<view class="nut-ellipsis-text" v-if="expandText" @click.stop="clickHandle(1)">{{ expandText }}</view
-        >{{ ellipsis.tailing }}
+        >{{ ellipsis.tailing && symbol }}{{ ellipsis.tailing }}
       </view>
       <view v-if="exceeded && expanded">
         {{ content }}
@@ -14,15 +14,16 @@
       </view>
     </view>
 
-    <view
-      class="nut-ellipsis-copy"
-      @click="handleClick"
-      ref="rootContain"
-      :id="'rootContain' + refRandomId"
-      :style="{ width: widthRef }"
-    >
+    <view class="nut-ellipsis-copy" ref="rootContain" :id="'rootContain' + refRandomId" :style="{ width: widthRef }">
       <view>{{ contantCopy }}</view>
     </view>
+
+    <!-- 省略号 symbol  -->
+    <view class="nut-ellipsis-copy" ref="symbolContain" :id="'symbolContain' + refRandomId" style="display: inline">{{
+      symbolText
+    }}</view>
+
+    <!-- 数字 9 英文 W  -->
   </view>
 </template>
 
@@ -30,7 +31,7 @@
 import { ref, reactive, toRefs, computed, onMounted, PropType, watch, unref } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useTaroRect } from '@/packages/utils/useTaroRect';
-import Taro from '@tarojs/taro';
+import Taro, { nextTick } from '@tarojs/taro';
 const { componentName, create } = createComponent('ellipsis');
 export type Direction = 'start' | 'end' | 'middle';
 
@@ -75,12 +76,13 @@ export default create({
   setup(props, { emit }) {
     const root = ref(null);
     const rootContain = ref(null);
+    const symbolContain = ref(null);
     let contantCopy = ref(props.content);
     let container: any = null;
     let maxHeight = 0; // 超出的最大高度
     let lineHeight = 0; // 当行的最大高度
     let originHeight = 0; // 原始高度
-    const ellipsis = ref<EllipsisedValue>();
+    const ellipsis = reactive<EllipsisedValue>({});
     const refRandomId = Math.random().toString(36).slice(-8);
     let widthRef = ref('auto');
     const state = reactive({
@@ -88,30 +90,39 @@ export default create({
       expanded: false //是否折叠
     });
 
+    let widthBase = [14, 10, 7, 8.4, 10]; // 中、英(大)、英(小)、数字、其他字符的基础宽度
+    let symbolTextWidth = widthBase[0] * 0.7921;
+    const chineseReg = /^[\u4e00-\u9fa5]+$/; // 汉字
+    const digitReg = /^[0-9]+$/; // 数字
+    const letterUpperReg = /^[A-Z]+$/; //字母
+    const letterLowerReg = /^[a-z]+$/; //字母
+
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
+        ell: true,
         [prefixCls]: true
       };
     });
 
-    watch(
-      () => props.content,
-      (newV, oldVal) => {
-        if (newV != oldVal) {
-          if (container) {
-            // document.body.appendChild(container);
-          }
-          // createContainer();
-        }
+    const symbolText = computed(() => {
+      if (props.direction == 'end' || props.direction == 'middle') {
+        return `${props.symbol}${props.expandText}`;
       }
-    );
+      return `${props.symbol}${props.expandText}${props.symbol}`;
+    });
 
     onMounted(() => {
       setTimeout(() => {
+        getSymbolInfo();
         getReference();
-      }, 500);
+      }, 100);
     });
+    // 获取省略号宽度
+    const getSymbolInfo = async () => {
+      const refe = await useTaroRect(symbolContain, Taro);
+      symbolTextWidth = refe.width ? Math.ceil(refe.width) : Math.ceil(widthBase[0] * 0.7921);
+    };
 
     const getReference = async () => {
       let element = unref(root);
@@ -122,9 +133,10 @@ export default create({
           .select(`#${(element as any).id}`)
           .fields(
             {
-              computedStyle: ['width', 'height', 'lineHeight', 'paddingTop', 'paddingBottom']
+              computedStyle: ['width', 'height', 'lineHeight', 'paddingTop', 'paddingBottom', 'fontSize']
             },
             (res) => {
+              console.log(res);
               lineHeight = pxToNumber(res.lineHeight === 'normal' ? props.lineHeight : res.lineHeight);
               maxHeight = Math.floor(
                 lineHeight * (Number(props.rows) + 0.5) + pxToNumber(res.paddingTop) + pxToNumber(res.paddingBottom)
@@ -134,6 +146,10 @@ export default create({
 
               widthRef.value = res.width;
 
+              // 设置基础字符
+              const bsize = pxToNumber(res.fontSize);
+              widthBase = [bsize, bsize * 0.72, bsize * 0.53, bsize * 0.4, bsize * 0.75];
+
               calcEllipse();
             }
           )
@@ -151,93 +167,95 @@ export default create({
 
         if (props.direction === 'middle') {
           const end = props.content.length;
-          tailorMiddle(
-            [0, rowNum * (Number(props.rows) + 0.5)],
-            [props.content.length - rowNum * (Number(props.rows) + 0.5), end]
-          );
+          ellipsis.leading = tailorContent(0, rowNum * (Number(props.rows) + 0.5), 'end');
+          ellipsis.tailing = tailorContent(props.content.length - rowNum * (Number(props.rows) + 0.5), end, 'start');
         } else if (props.direction === 'end') {
           const end = rowNum * (Number(props.rows) + 0.5);
-          tailor(0, end);
+          ellipsis.leading = tailorContent(0, end);
         } else {
           const start = props.content.length - rowNum * (Number(props.rows) + 0.5) - 5;
 
-          tailor(start, props.content.length);
+          ellipsis.tailing = tailorContent(start, props.content.length);
         }
+
+        // 进行兜底判断,是否符合要求
+        assignContent();
+        setTimeout(() => {
+          verifyEllipsis();
+        }, 100);
       }
     };
 
-    // 计算 start/end 省略
-    const tailor = async (left: number, right: number) => {
-      const actionText = state.expanded ? props.collapseText : props.expandText;
-      const end = props.content.length;
-
-      if (right - left <= 1) {
-        state.exceeded = true;
-        if (props.direction === 'end') {
-          (ellipsis as any).value = {
-            leading: props.content.slice(0, left) + props.symbol
-          };
+    // 验证省略号
+    const verifyEllipsis = async () => {
+      const refe = await useTaroRect(rootContain, Taro);
+      if (refe && refe.height && refe.height > maxHeight) {
+        if (props.direction == 'end') {
+          ellipsis.leading = ellipsis.leading?.slice(0, ellipsis.leading.length - 1);
         } else {
-          (ellipsis as any).value = {
-            tailing: props.symbol + props.content.slice(right, end)
-          };
+          ellipsis.tailing = ellipsis.tailing?.slice(1, ellipsis.tailing.length);
         }
-        return false;
+
+        assignContent();
+        setTimeout(() => {
+          verifyEllipsis();
+        }, 100);
       }
-      const middle = Math.round((left + right) / 2);
+    };
+
+    const assignContent = () => {
+      contantCopy.value = `${ellipsis.leading || ''}${ellipsis.leading ? props.symbol : ''}${props.expandText || ''}${
+        ellipsis.tailing ? props.symbol : ''
+      }${ellipsis.tailing || ''}`;
+    };
+    // 计算省略号
+    const tailorContent = (left: number, right: number, type = '') => {
+      const threeDotWidth = symbolTextWidth;
 
-      if (props.direction === 'end') {
-        contantCopy.value = props.content.slice(0, middle) + props.symbol + actionText;
+      const direc = props.direction === 'middle' && type ? type : props.direction;
+
+      state.exceeded = true;
+
+      let widthPart = -1;
+      let start = left;
+      let end = right;
+      let cutoff = 0;
+      let marking = 0;
+
+      if (direc === 'end') {
+        marking = start;
+        cutoff = end;
       } else {
-        contantCopy.value = actionText + props.symbol + props.content.slice(middle, end);
+        marking = end;
+        cutoff = start;
       }
-      setTimeout(async () => {
-        const refe = await useTaroRect(rootContain, Taro);
-        if (refe.height <= maxHeight) {
-          if (props.direction === 'end') {
-            tailor(middle, right);
-          } else {
-            tailor(left, middle);
-          }
+
+      let contentWidth = pxToNumber(widthRef.value) * Number(props.rows) - threeDotWidth;
+      let contentPartWidth = props.direction === 'middle' ? contentWidth / 2 : contentWidth;
+
+      while (widthPart < contentPartWidth) {
+        const zi = props.content[marking];
+        if (chineseReg.test(zi)) {
+          widthPart = Number(widthPart + widthBase[0]);
+        } else if (letterUpperReg.test(zi)) {
+          widthPart = Number(widthPart + widthBase[1]);
+        } else if (letterLowerReg.test(zi)) {
+          widthPart = Number(widthPart + widthBase[2]);
+        } else if (digitReg.test(zi)) {
+          widthPart = Number(widthPart + widthBase[3]);
         } else {
-          if (props.direction === 'end') {
-            tailor(left, middle);
-          } else {
-            tailor(middle, right);
-          }
+          widthPart = Number(widthPart + widthBase[4]);
         }
-      }, 10);
-    };
-    // 计算 middle 省略
-    const tailorMiddle = async (leftPart: [number, number], rightPart: [number, number]) => {
-      const actionText = state.expanded ? props.collapseText : props.expandText;
-      const end = props.content.length;
-      if (leftPart[1] - leftPart[0] <= 1 && rightPart[1] - rightPart[0] <= 1) {
-        state.exceeded = true;
-        (ellipsis as any).value = {
-          leading: props.content.slice(0, leftPart[0]) + props.symbol,
-          tailing: props.symbol + props.content.slice(rightPart[1], end)
-        };
-        return false;
+        cutoff = marking;
+
+        direc === 'end' ? marking++ : marking--;
+      }
+
+      if (direc === 'end') {
+        return props.content.slice(0, cutoff);
+      } else {
+        return props.content.slice(cutoff, end);
       }
-      const leftPartMiddle = Math.floor((leftPart[0] + leftPart[1]) / 2);
-      const rightPartMiddle = Math.ceil((rightPart[0] + rightPart[1]) / 2);
-
-      contantCopy.value =
-        props.content.slice(0, leftPartMiddle) +
-        props.symbol +
-        actionText +
-        props.symbol +
-        props.content.slice(rightPartMiddle, end);
-
-      setTimeout(async () => {
-        const refe = await useTaroRect(rootContain, Taro);
-        if (refe.height <= maxHeight) {
-          tailorMiddle([leftPartMiddle, leftPart[1]], [rightPart[0], rightPartMiddle]);
-        } else {
-          tailorMiddle([leftPart[0], leftPartMiddle], [rightPartMiddle, rightPart[1]]);
-        }
-      }, 10);
     };
 
     const pxToNumber = (value: string | null) => {
@@ -266,9 +284,11 @@ export default create({
       ...toRefs(state),
       root,
       rootContain,
+      symbolContain,
       ellipsis,
       classes,
       contantCopy,
+      symbolText,
       clickHandle,
       handleClick,
       refRandomId,

+ 4 - 4
src/packages/__VUE/ellipsis/index.vue

@@ -1,10 +1,10 @@
 <template>
   <view :class="classes" @click="handleClick" ref="root">
     <view v-if="!exceeded">{{ content }}</view>
-    <view v-if="exceeded && !expanded">
-      {{ ellipsis.leading }}
-      <span class="nut-ellipsis-text" v-if="expandText" @click.stop="clickHandle(1)">{{ expandText }}</span>
-      {{ ellipsis.tailing }}
+    <view v-if="exceeded && !expanded"
+      >{{ ellipsis.leading
+      }}<span class="nut-ellipsis-text" v-if="expandText" @click.stop="clickHandle(1)">{{ expandText }}</span
+      >{{ ellipsis.tailing }}
     </view>
     <view v-if="exceeded && expanded">
       {{ content }}

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

@@ -24,7 +24,7 @@
 
       <!-- Taro 下转换成 微信小程序 -->
       <picker-view
-        v-if="ENV == ENV_TYPE.WEAPP"
+        v-if="ENV != ENV_TYPE.WEB"
         indicator-style="height: 34px;"
         :value="defaultIndexes"
         style="width: 100%; height: 252px"

+ 10 - 0
src/packages/__VUE/uploader/__tests__/index.spec.ts

@@ -266,3 +266,13 @@ test('multiFile upload filter max-size file', async () => {
   await sleep();
   // expect(wrapper.emitted<[File]>('oversize')![0]).toBeTruthy();
 });
+
+test('delete-icon prop', () => {
+  const wrapper = mount(Uploader, {
+    props: {
+      deleteIcon: 'dongdong'
+    }
+  });
+
+  expect(wrapper.html()).toMatchSnapshot();
+});

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

@@ -390,7 +390,7 @@ export default {
 | before-upload     | Hook before reading the file, return false to stop reading the file, can return Promise                                                          | Function                          | null             |
 | before-xhr-upload`v3.2.1` | Customize the method when uploading XHR                                                                                                                                                                          | Function(xhr,option)                          | null             |
 | before-delete     | Hook before delete the file, return false to stop reading the file, can return Promise                                                           | Function(file,fileList): boolean 丨Promise | -                |
-
+| delete-icon               | Customize the delete button by passing in [icon name](/#/en-US/component/icon) or an image link                                                                                                                                                   | String                            | "photograph"     |
 
 
 ### FileItem

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

@@ -390,6 +390,7 @@ export default {
 | before-upload             | 上传前的函数需要返回一个`Promise`对象                                                                                                                                                  | Function                          | null             |
 | before-xhr-upload`v3.2.1` | 执行 XHR 上传时,自定义方式                                                                                                                                                            | Function(xhr,option)             | null             |
 | before-delete             | 除文件时的回调,返回值为 false 时不移除。支持返回一个 `Promise` 对象,`Promise` 对象 resolve(false) 或 reject 时不移除                                                                 | Function(file,fileList): boolean 丨Promise | -                |
+| delete-icon               | 自定义删除按钮,可传入[图标名称](/#/zh-CN/component/icon)或图片链接                                                                                                                                                   | String                            | "photograph"     |
 
 > 注意:accept、capture 和 multiple 为浏览器 input 标签的原生属性,移动端各种机型对这些属性的支持程度有所差异,因此在不同机型和 WebView 下可能出现一些兼容性问题。
 

+ 1 - 1
src/packages/__VUE/uploader/doc.taro.md

@@ -255,7 +255,7 @@ setup() {
 | before-upload             | 上传前的函数需要返回一个`Promise`对象                                                                                  | Function                          | null                      |
 | before-xhr-upload`v3.2.1` | 执行 Taro.uploadFile 上传时,自定义方式                                                                                | Function(Taro.uploadFile,option) | null                      |
 | before-delete             | 除文件时的回调,返回值为 false 时不移除。支持返回一个 `Promise` 对象,`Promise` 对象 resolve(false) 或 reject 时不移除 | Function(file,fileList): boolean 丨Promise | -                         |
-
+| delete-icon               | 自定义删除按钮,可传入[图标名称](/#/zh-CN/component/icon)或图片链接                                                                                                                                                   | String                            | "photograph"     |
 
 
 ### FileItem

+ 8 - 1
src/packages/__VUE/uploader/index.taro.vue

@@ -16,7 +16,13 @@
           <nut-icon color="#fff" :name="item.status == 'error' ? 'failure' : 'loading'"></nut-icon>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
         </view>
-        <nut-icon v-if="isDeletable" @click="onDelete(item, index)" class="close" name="failure"></nut-icon>
+        <nut-icon
+          v-if="isDeletable"
+          v-bind="$attrs"
+          @click="onDelete(item, index)"
+          class="close"
+          :name="deleteIcon"
+        ></nut-icon>
         <img
           class="nut-uploader__preview-img__c"
           @click="fileItemClick(item)"
@@ -102,6 +108,7 @@ export default create({
     multiple: { type: Boolean, default: true },
     disabled: { type: Boolean, default: false },
     autoUpload: { type: Boolean, default: true },
+    deleteIcon: { type: String, default: 'failure' },
     beforeUpload: {
       type: Function,
       default: null

+ 8 - 1
src/packages/__VUE/uploader/index.vue

@@ -36,7 +36,13 @@
           <nut-icon color="#fff" :name="item.status == 'error' ? 'failure' : 'loading'"></nut-icon>
           <view class="nut-uploader__preview__progress__msg">{{ item.message }}</view>
         </view>
-        <nut-icon v-if="isDeletable" @click="onDelete(item, index)" class="close" name="failure"></nut-icon>
+        <nut-icon
+          v-if="isDeletable"
+          v-bind="$attrs"
+          @click="onDelete(item, index)"
+          class="close"
+          :name="deleteIcon"
+        ></nut-icon>
         <img
           class="nut-uploader__preview-img__c"
           @click="fileItemClick(item)"
@@ -134,6 +140,7 @@ export default create({
     multiple: { type: Boolean, default: false },
     disabled: { type: Boolean, default: false },
     autoUpload: { type: Boolean, default: true },
+    deleteIcon: { type: String, default: 'failure' },
     beforeUpload: {
       type: Function,
       default: null

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

@@ -33,8 +33,8 @@
           "scene": null
         },
         {
-          "name": "business/pages/signature/index",
-          "pathName": "business/pages/signature/index",
+          "name": "exhibition/pages/ellipsis/index",
+          "pathName": "exhibition/pages/ellipsis/index",
           "query": "",
           "launchMode": "default",
           "scene": null
@@ -63,5 +63,6 @@
       ]
     }
   },
-  "projectname": "vue"
+  "projectname": "vue",
+  "libVersion": "2.27.1"
 }