Browse Source

feat: price、avatar taro适配和优化 (#502)

* feat: price、avatar taro适配和优化

* fix: 修改avatar demo

Co-authored-by: ailululu <ailu@jd.com>
ailululu 4 years ago
parent
commit
fb3070a49d

+ 2 - 0
src/config.json

@@ -259,6 +259,7 @@
         },
         {
           "name": "Price",
+          "taro": true,
           "sort": 4,
           "cName": "价格组件",
           "type": "component",
@@ -297,6 +298,7 @@
         },
         {
           "name": "Avatar",
+          "taro": true,
           "sort": 7,
           "cName": "头像",
           "type": "component",

+ 19 - 12
src/packages/__VUE/avatar/demo.vue

@@ -4,39 +4,43 @@
     <nut-cell>
       <nut-avatar
         size="large"
-        src="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
       >
       </nut-avatar>
       <nut-avatar
         size="normal"
-        src="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
       >
       </nut-avatar>
       <nut-avatar
         size="small"
-        src="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
       >
       </nut-avatar>
     </nut-cell>
     <h2>修改形状</h2>
     <nut-cell>
-      <nut-avatar shape="square"></nut-avatar>
-      <nut-avatar shape="round"></nut-avatar>
+      <nut-avatar icon="my" shape="square"></nut-avatar>
+      <nut-avatar icon="my" shape="round"></nut-avatar>
     </nut-cell>
     <h2>修改背景色</h2>
     <nut-cell>
-      <nut-avatar bg-color="#FA2C19"></nut-avatar>
+      <nut-avatar class="demo-avatar" icon="my" bg-color="#FA2C19"></nut-avatar>
     </nut-cell>
-    <h2>修改背景Icon</h2>
+    <h2>修改背景图片</h2>
     <nut-cell>
       <nut-avatar
-        icon="https://img30.360buyimg.com/uba/jfs/t1/84318/29/2102/10483/5d0704c1Eb767fa74/fc456b03fdd6cbab.png"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png"
       >
       </nut-avatar>
     </nut-cell>
     <h2>可以修改头像的内容</h2>
     <nut-cell>
-      <nut-avatar icon>N</nut-avatar>
+      <nut-avatar>N</nut-avatar>
+    </nut-cell>
+    <h2>点击头像触发事件</h2>
+    <nut-cell>
+      <nut-avatar icon="my" @activeAvatar="handleClick"></nut-avatar>
     </nut-cell>
   </div>
 </template>
@@ -46,10 +50,10 @@ const { createDemo } = createComponent('avatar');
 export default createDemo({
   props: {},
   setup() {
-    const onError = (e: Event) => {
-      console.error(e);
+    const handleClick = () => {
+      console.log('触发点击头像');
     };
-    return { onError };
+    return { handleClick };
   }
 });
 </script>
@@ -58,4 +62,7 @@ export default createDemo({
   align-items: flex-end;
   border-radius: 0;
 }
+.demo-avatar {
+  color: #fff;
+}
 </style>

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

@@ -13,6 +13,10 @@
     left: 50%;
     transform: translate(-50%, -50%);
   }
+  .nut-icon__img {
+    width: 100%;
+    height: 100%;
+  }
   .text {
     display: inline-block;
     width: 100%;

+ 77 - 0
src/packages/__VUE/avatar/index.taro.vue

@@ -0,0 +1,77 @@
+<template>
+  <view :style="styles" :class="classes" @click="activeAvatar(e)">
+    <nut-icon class="icon" :name="iconStyles"></nut-icon>
+    <view class="text" v-if="isShowText">
+      <slot></slot>
+    </view>
+  </view>
+</template>
+<script lang="ts">
+import { toRefs, computed } from 'vue';
+import { createComponent } from '@/packages/utils/create';
+const { componentName, create } = createComponent('avatar');
+export default create({
+  props: {
+    size: {
+      type: String,
+      default: 'normal'
+    },
+    shape: {
+      type: String,
+      default: 'round'
+    },
+    bgColor: {
+      type: String,
+      default: '#eee'
+    },
+    icon: {
+      type: String,
+      default: ''
+    }
+  },
+  emits: ['active-avatar'],
+  setup(props, { emit, slots }) {
+    const { size, shape, bgColor, icon } = toRefs(props);
+    const sizeValue = ['large', 'normal', 'small'];
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      return {
+        [prefixCls]: true,
+        ['avatar-' + size.value]: true,
+        ['avatar-' + shape.value]: true
+      };
+    });
+
+    const styles = computed(() => {
+      return {
+        width: sizeValue.indexOf(size.value) > -1 ? '' : `${size.value}px`,
+        height: sizeValue.indexOf(size.value) > -1 ? '' : `${size.value}px`,
+        backgroundColor: `${bgColor.value}`
+      };
+    });
+
+    const iconStyles = computed(() => {
+      return !!icon.value ? icon.value : '';
+    });
+
+    const isShowText = computed(() => {
+      return slots.default;
+    });
+
+    const activeAvatar = (event: any) => {
+      emit('active-avatar', event);
+    };
+
+    return {
+      classes,
+      styles,
+      iconStyles,
+      isShowText,
+      activeAvatar
+    };
+  }
+});
+</script>
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 8 - 14
src/packages/__VUE/avatar/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <view :style="styles" :class="classes" @click="activeAvatar">
+  <view :style="styles" :class="classes" @click="activeAvatar(e)">
     <nut-icon class="icon" :name="iconStyles"></nut-icon>
     <view class="text" v-if="isShowText">
       <slot></slot>
@@ -27,15 +27,11 @@ export default create({
     icon: {
       type: String,
       default: ''
-    },
-    src: {
-      type: String,
-      default: ''
     }
   },
-  emits: ['on-error'],
+  emits: ['active-avatar'],
   setup(props, { emit, slots }) {
-    const { size, shape, bgColor, icon, src } = toRefs(props);
+    const { size, shape, bgColor, icon } = toRefs(props);
     const sizeValue = ['large', 'normal', 'small'];
     const classes = computed(() => {
       const prefixCls = componentName;
@@ -50,30 +46,28 @@ export default create({
       return {
         width: sizeValue.indexOf(size.value) > -1 ? '' : `${size.value}px`,
         height: sizeValue.indexOf(size.value) > -1 ? '' : `${size.value}px`,
-        backgroundImage: src.value ? `url(${src.value})` : null,
         backgroundColor: `${bgColor.value}`
       };
     });
 
     const iconStyles = computed(() => {
-      return !!icon.value && !src.value ? icon.value : '';
+      return !!icon.value ? icon.value : '';
     });
 
     const isShowText = computed(() => {
       return slots.default;
     });
 
-    let image = new Image();
-    image.src = props.src;
-    image.onerror = event => {
-      emit('on-error', event);
+    const activeAvatar = (event: any) => {
+      emit('active-avatar', event);
     };
 
     return {
       classes,
       styles,
       iconStyles,
-      isShowText
+      isShowText,
+      activeAvatar
     };
   }
 });

+ 2 - 2
src/packages/__VUE/price/demo.vue

@@ -2,7 +2,7 @@
   <div class="demo">
     <h2>基本用法</h2>
     <nut-cell>
-      <nut-price :price="1010" :need-symbol="false" :thousands="true" />
+      <nut-price :price="0" :need-symbol="false" :thousands="true" />
     </nut-cell>
     <h2>有人民币符号,无千位分隔</h2>
     <nut-cell>
@@ -11,7 +11,7 @@
     <h2>带人民币符号,有千位分隔,保留小数点后三位</h2>
     <nut-cell>
       <nut-price
-        :price="15213.1221"
+        :price="15213.123"
         :decimal-digits="3"
         :need-symbol="true"
         :thousands="true"

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

@@ -3,16 +3,20 @@
   display: inline;
   color: $primary-color;
   &--symbol {
+    display: inline-block;
     font-size: $font-size-3;
     margin-right: 4px;
   }
   &--big {
+    display: inline-block;
     font-size: $price-big-size;
   }
   &--point {
+    display: inline-block;
     font-size: $price-big-size;
   }
   &--small {
+    display: inline-block;
     font-size: $font-size-4;
   }
 }

+ 147 - 0
src/packages/__VUE/price/index.taro.vue

@@ -0,0 +1,147 @@
+<template>
+  <view :class="classes">
+    <text
+      v-if="needSymbol"
+      class="nut-price--symbol"
+      decode="true"
+      v-html="showSymbol"
+    ></text>
+    <view class="nut-price--big">
+      {{ formatThousands(price) }}
+    </view>
+    <view class="nut-price--point">.</view>
+    <view class="nut-price--small">
+      {{ formatDecimal(price) }}
+    </view>
+  </view>
+</template>
+
+<script lang="ts">
+import { computed } from 'vue';
+import { createComponent } from '@/packages/utils/create';
+const { componentName, create } = createComponent('price');
+
+export default create({
+  props: {
+    price: {
+      type: [Number, String],
+      default: 0
+    },
+    needSymbol: {
+      type: Boolean,
+      default: true
+    },
+    symbol: {
+      type: String,
+      default: '&yen;'
+    },
+    decimalDigits: {
+      type: Number,
+      default: 2
+    },
+    thousands: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  setup(props) {
+    const classes = computed(() => {
+      return {
+        [componentName]: true
+      };
+    });
+    const replaceSpecialChar = (url: string) => {
+      url = url.replace(/&quot;/g, '"');
+      url = url.replace(/&amp;/g, '&');
+      url = url.replace(/&lt;/g, '<');
+      url = url.replace(/&gt;/g, '>');
+      url = url.replace(/&nbsp;/g, ' ');
+      url = url.replace(/&yen;/g, '¥');
+      console.log('转义字符', url);
+      return url;
+    };
+    const showSymbol = computed(() => {
+      const symbol = props.needSymbol ? replaceSpecialChar(props.symbol) : '';
+      return symbol;
+    });
+    const checkPoint = (price: string | number) => {
+      return String(price).indexOf('.') > 0;
+    };
+
+    // const formatToHump = (price: any) => {
+    //   if (Number(price) == 0) {
+    //     price = 0;
+    //   }
+    //   if (checkPoint(price)) {
+    //     price = Number(price).toFixed(props.decimalDigits);
+    //     price = typeof price.split('.') === 'string' ? price.split('.') : price.split('.')[0]
+    //   } else {
+    //     price = price.toString()
+    //   }
+    // };
+
+    const formatThousands = (num: any) => {
+      console.log('num', num, typeof num);
+      // formatToHump(num)
+      if (Number(num) == 0) {
+        num = 0;
+      }
+      if (checkPoint(num)) {
+        num = Number(num).toFixed(props.decimalDigits);
+        console.log('num1', num, typeof num);
+        // return rendernum(num.split('.'));
+        num =
+          typeof num.split('.') === 'string'
+            ? num.split('.')
+            : num.split('.')[0];
+      } else {
+        num = num.toString();
+      }
+      console.log('num2', num, typeof num);
+      if (props.thousands) {
+        console.log(
+          '33',
+          (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
+        );
+        return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
+      } else {
+        return num;
+      }
+    };
+    const formatDecimal = (decimalNum: any) => {
+      // formatToHump(decimalNum)
+      if (Number(decimalNum) == 0) {
+        decimalNum = 0;
+      }
+      if (checkPoint(decimalNum)) {
+        decimalNum = Number(decimalNum).toFixed(props.decimalDigits);
+        console.log('decimalNum1', decimalNum, typeof decimalNum);
+        // return renderdecimalNum(decimalNum.split('.'));
+        decimalNum =
+          typeof decimalNum.split('.') === 'string'
+            ? 0
+            : decimalNum.split('.')[1];
+      } else {
+        decimalNum = decimalNum.toString();
+      }
+      console.log('decimalNum1', decimalNum);
+      const result = '0.' + decimalNum;
+      const resultFixed = Number(result).toFixed(props.decimalDigits);
+      return String(resultFixed).substring(2, resultFixed.length);
+    };
+    return {
+      classes,
+      showSymbol,
+      checkPoint,
+      formatThousands,
+      formatDecimal,
+      replaceSpecialChar
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 75 - 32
src/packages/__VUE/price/index.vue

@@ -1,5 +1,18 @@
 <template>
-  <view :class="classes" v-html="priceShow"> </view>
+  <view :class="classes">
+    <view
+      v-if="needSymbol"
+      class="nut-price--symbol"
+      v-html="showSymbol"
+    ></view>
+    <view class="nut-price--big">
+      {{ formatThousands(price) }}
+    </view>
+    <view class="nut-price--point">.</view>
+    <view class="nut-price--small">
+      {{ formatDecimal(price) }}
+    </view>
+  </view>
 </template>
 
 <script lang="ts">
@@ -32,56 +45,86 @@ export default create({
   },
 
   setup(props) {
-    const priceShow = computed(() => {
-      const symbol = props.needSymbol
-        ? `<view class="${componentName}--symbol">${props.symbol}</view>`
-        : '';
-      return symbol + formatToHump(props.price);
-    });
     const classes = computed(() => {
       return {
         [componentName]: true
       };
     });
-
+    const showSymbol = computed(() => {
+      const symbol = props.needSymbol ? props.symbol : '';
+      return symbol;
+    });
     const checkPoint = (price: string | number) => {
       return String(price).indexOf('.') > 0;
     };
-    const formatThousands = (num: string | number) => {
+
+    // const formatToHump = (price: any) => {
+    //   if (Number(price) == 0) {
+    //     price = 0;
+    //   }
+    //   if (checkPoint(price)) {
+    //     price = Number(price).toFixed(props.decimalDigits);
+    //     price = typeof price.split('.') === 'string' ? price.split('.') : price.split('.')[0]
+    //   } else {
+    //     price = price.toString()
+    //   }
+    // };
+
+    const formatThousands = (num: any) => {
+      console.log('num', num, typeof num);
+      // formatToHump(num)
+      if (Number(num) == 0) {
+        num = 0;
+      }
+      if (checkPoint(num)) {
+        num = Number(num).toFixed(props.decimalDigits);
+        console.log('num1', num, typeof num);
+        // return rendernum(num.split('.'));
+        num =
+          typeof num.split('.') === 'string'
+            ? num.split('.')
+            : num.split('.')[0];
+      } else {
+        num = num.toString();
+      }
+      console.log('num2', num, typeof num);
       if (props.thousands) {
+        console.log(
+          '33',
+          (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
+        );
         return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
       } else {
         return num;
       }
     };
-    const formatDecimal = (decimalNum: string | number) => {
-      const result = '0.' + decimalNum;
-      const resultFixed = Number(result).toFixed(props.decimalDigits);
-      return String(resultFixed).substring(2, resultFixed.length);
-    };
-
-    const renderPrice = (price: string[] | string) => {
-      return `<view class="${componentName}--big">${formatThousands(
-        typeof price === 'string' ? price : price[0]
-      )}</view><view class="${componentName}--point">.</view><view class="${componentName}--small">${formatDecimal(
-        typeof price === 'string' ? 0 : price[1]
-      )}</view>`;
-    };
-
-    const formatToHump = (price: string | number) => {
-      if (Number(price) == 0) {
-        return 0;
+    const formatDecimal = (decimalNum: any) => {
+      // formatToHump(decimalNum)
+      if (Number(decimalNum) == 0) {
+        decimalNum = 0;
       }
-      if (checkPoint(price)) {
-        price = Number(price).toFixed(props.decimalDigits);
-        return renderPrice(price.split('.'));
+      if (checkPoint(decimalNum)) {
+        decimalNum = Number(decimalNum).toFixed(props.decimalDigits);
+        console.log('decimalNum1', decimalNum, typeof decimalNum);
+        // return renderdecimalNum(decimalNum.split('.'));
+        decimalNum =
+          typeof decimalNum.split('.') === 'string'
+            ? 0
+            : decimalNum.split('.')[1];
       } else {
-        return renderPrice(price.toString());
+        decimalNum = decimalNum.toString();
       }
+      console.log('decimalNum1', decimalNum);
+      const result = '0.' + decimalNum;
+      const resultFixed = Number(result).toFixed(props.decimalDigits);
+      return String(resultFixed).substring(2, resultFixed.length);
     };
     return {
-      priceShow,
-      classes
+      classes,
+      showSymbol,
+      checkPoint,
+      formatThousands,
+      formatDecimal
     };
   }
 });

+ 2 - 0
src/sites/mobile-taro/vue/src/app.config.ts

@@ -23,6 +23,8 @@ export default {
     'pages/checkbox/index',
     'pages/button/index',
     'pages/switch/index',
+    'pages/price/index',
+    'pages/avatar/index',
     'pages/layout/index',
     'pages/index/index'
   ],

+ 3 - 0
src/sites/mobile-taro/vue/src/pages/avatar/index.config.ts

@@ -0,0 +1,3 @@
+export default {
+  navigationBarTitleText: 'Avatar'
+};

+ 66 - 0
src/sites/mobile-taro/vue/src/pages/avatar/index.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="demo full">
+    <h2>默认用法 (内置"small","normal","large"三种尺寸规格)</h2>
+    <nut-cell>
+      <nut-avatar
+        size="large"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+      >
+      </nut-avatar>
+      <nut-avatar
+        size="normal"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+      >
+      </nut-avatar>
+      <nut-avatar
+        size="small"
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png"
+      >
+      </nut-avatar>
+    </nut-cell>
+    <h2>修改形状</h2>
+    <nut-cell>
+      <nut-avatar icon="my" shape="square"></nut-avatar>
+      <nut-avatar icon="my" shape="round"></nut-avatar>
+    </nut-cell>
+    <h2>修改背景色</h2>
+    <nut-cell>
+      <nut-avatar class="demo-avatar" icon="my" bg-color="#FA2C19"></nut-avatar>
+    </nut-cell>
+    <h2>修改背景图片</h2>
+    <nut-cell>
+      <nut-avatar
+        icon="https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png"
+      >
+      </nut-avatar>
+    </nut-cell>
+    <h2>可以修改头像的内容</h2>
+    <nut-cell>
+      <nut-avatar>N</nut-avatar>
+    </nut-cell>
+    <h2>点击头像触发事件</h2>
+    <nut-cell>
+      <nut-avatar icon="my" @activeAvatar="handleClick"></nut-avatar>
+    </nut-cell>
+  </div>
+</template>
+<script lang="ts">
+export default {
+  props: {},
+  setup() {
+    const handleClick = () => {
+      console.log('触发点击头像');
+    };
+    return { handleClick };
+  }
+};
+</script>
+<style lang="scss">
+.nut-cell {
+  align-items: flex-end;
+  border-radius: 0;
+}
+.demo-avatar {
+  color: #fff;
+}
+</style>

+ 3 - 0
src/sites/mobile-taro/vue/src/pages/price/index.config.ts

@@ -0,0 +1,3 @@
+export default {
+  navigationBarTitleText: 'Price'
+};

+ 48 - 0
src/sites/mobile-taro/vue/src/pages/price/index.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="demo">
+    <h2>基本用法&yen;</h2>
+    <nut-cell>
+      <nut-price :price="1010" :need-symbol="false" :thousands="true" />
+    </nut-cell>
+    <h2>有人民币符号,无千位分隔</h2>
+    <nut-cell>
+      <nut-price :price="10010.01" :need-symbol="true" :thousands="false" />
+    </nut-cell>
+    <h2>带人民币符号,有千位分隔,保留小数点后三位</h2>
+    <nut-cell>
+      <nut-price
+        :price="15213.1221"
+        :decimal-digits="3"
+        :need-symbol="true"
+        :thousands="true"
+      />
+    </nut-cell>
+    <h2>异步随机变更</h2>
+    <nut-cell>
+      <nut-price
+        :price="price"
+        :decimal-digits="3"
+        :need-symbol="false"
+        :thousands="true"
+      />
+    </nut-cell>
+  </div>
+</template>
+
+<script lang="ts">
+import { ref } from 'vue';
+export default {
+  setup() {
+    const price = ref(0);
+    setInterval(() => {
+      price.value = Math.random() * 10000000;
+      // console.log('price.value1', price.value)
+    }, 1000);
+    return {
+      price
+    };
+  }
+};
+</script>
+
+<style lang="scss"></style>