ソースを参照

upd: imagepreview优化 (#706)

* feat: searchbar 完成,适配 taro

* upd: imageprevi 优化
JackieScorpio 4 年 前
コミット
f2b51732db

+ 11 - 0
src/config.json

@@ -510,6 +510,17 @@
           "show": true,
           "taro": true,
           "author": "yangxiaolu"
+        },
+        {
+          "version": "3.0.0",
+          "name": "SearchBar",
+          "type": "component",
+          "cName": "搜索栏",
+          "desc": "搜索栏",
+          "sort": 23,
+          "show": true,
+          "taro": true,
+          "author": "zongyue3"
         }
       ]
     },

+ 3 - 3
src/packages/__VUE/imagepreview/doc.md

@@ -10,13 +10,13 @@
 import { createApp, reactive, toRefs } from 'vue';
 
 // vue
-import { ImagePreview, Swiper, SwiperItem, Popup } from '@nutui/nutui';
+import { ImagePreview } from '@nutui/nutui';
 // taro
-import { ImagePreview, Swiper, SwiperItem, Popup } from '@nutui/nutui-taro';
+import { ImagePreview } from '@nutui/nutui-taro';
 
 
 const app = createApp();
-app.use(ImagePreview).use(Swiper).use(SwiperItem).use(Popup).use(Cell).use(Icon);
+app.use(ImagePreview);
 ```
 
 ### 基础用法

+ 4 - 1
src/packages/__VUE/imagepreview/index.taro.vue

@@ -20,6 +20,7 @@
 <script lang="ts">
 import { toRefs, reactive, watch } from 'vue';
 import { createComponent } from '../../utils/create';
+import Popup from '../popup/index.taro.vue';
 const { componentName, create } = createComponent('imagepreview');
 
 export default create({
@@ -33,7 +34,9 @@ export default create({
       default: () => []
     }
   },
-  components: {},
+  components: {
+    [Popup.name]: Popup
+  },
 
   setup(props, { emit }) {
     const { value, images } = toRefs(props);

+ 10 - 3
src/packages/__VUE/imagepreview/index.vue

@@ -20,6 +20,9 @@
 <script lang="ts">
 import { toRefs, reactive, watch } from 'vue';
 import { createComponent } from '../../utils/create';
+import Popup from '../popup/index.vue';
+import Swiper from '../swiper/index.vue';
+import SwiperItem from '../Swiperitem/index.vue';
 const { componentName, create } = createComponent('imagepreview');
 
 export default create({
@@ -33,13 +36,17 @@ export default create({
       default: () => []
     }
   },
-  components: {},
+  components: {
+    [Popup.name]: Popup,
+    [Swiper.name]: Swiper,
+    [SwiperItem.name]: SwiperItem
+  },
 
   setup(props, { emit }) {
-    const { value, images } = toRefs(props);
+    const { show, images } = toRefs(props);
 
     const state = reactive({
-      showPop: value,
+      showPop: show,
       active: 1
     });
 

+ 54 - 0
src/packages/__VUE/searchbar/demo.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-searchbar class="wrap" v-model="searchValue" @search="search">
+      <template v-slot:leftout>
+        <nut-icon @click="clickLeft" size="20" name="left"></nut-icon>
+      </template>
+      <template v-slot:leftin>
+        <nut-icon size="14" name="search2"></nut-icon>
+      </template>
+      <template v-slot:rightin>
+        <nut-icon size="20" name="photograph"></nut-icon>
+      </template>
+      <template v-slot:rightout>
+        <nut-icon size="20" name="message"></nut-icon>
+      </template>
+    </nut-searchbar>
+  </div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive } from 'vue';
+import { createComponent } from '../../utils/create';
+const { createDemo } = createComponent('searchbar');
+export default createDemo({
+  props: {},
+  setup() {
+    const state = reactive({
+      searchValue: ''
+    });
+
+    const search = function () {
+      console.log('ENTER clicked');
+    };
+
+    const clickLeft = function () {
+      console.log('left clicked');
+    };
+
+    return {
+      clickLeft,
+      search,
+      ...toRefs(state)
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.wrap {
+  height: 80px;
+  background: rgba(0, 0, 0, 0.1);
+}
+</style>

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

@@ -0,0 +1,92 @@
+# Searchbar组件
+
+### 介绍
+
+搜索栏
+    
+### 安装
+    
+```javascript
+import { createApp, reactive, toRefs } from 'vue';
+
+// vue
+import { SearchBar } from '@nutui/nutui';
+// taro
+import { SearchBar } from '@nutui/nutui-taro';
+
+
+const app = createApp();
+app.use(SearchBar);
+```    
+    
+### 基础用法
+
+```html
+<nut-searchbar class="wrap" v-model="searchValue" @search="search">
+    <template v-slot:leftout>
+    <nut-icon @click="clickLeft" size="20" name="left"></nut-icon>
+    </template>
+    <template v-slot:leftin>
+    <nut-icon size="14" name="search2"></nut-icon>
+    </template>
+    <template v-slot:rightin>
+    <nut-icon size="20" name="photograph"></nut-icon>
+    </template>
+    <template v-slot:rightout>
+    <nut-icon size="20" name="message"></nut-icon>
+    </template>
+</nut-searchbar>
+```
+
+```javascript
+ setup() {
+    const state = reactive({
+      searchValue: ""
+    });
+
+    const search = function () {
+      console.log('ENTER clicked');
+    }
+
+    const clickLeft = function () {
+      console.log('left clicked');
+    }
+
+    return {
+      clickLeft,
+      search,
+      ...toRefs(state),
+    };
+}
+```
+    
+### Props
+    
+| 参数         | 说明                             | 类型   | 默认值           |
+|--------------|----------------------------------|--------|------------------|
+| max-length         | 最大输入长度   | [Number,String] | '9999'      |
+| placeholder        | 输入框默认暗纹  | String | '请输入'   |
+| clearable          | 是否展示清除按钮 | Boolean | true     |
+| has-left-in     | 是否展示输入框内 左icon     | Boolean | true |
+| has-left-out     | 是否展示输入框外 左icon     | Boolean | true |
+| has-right-in     | 是否展示输入框内 右icon     | Boolean | true |
+| has-right-out     | 是否展示输入框外 右icon     | Boolean | true |
+
+### Events
+
+| 事件名 | 说明           | 回调参数     |
+|--------|----------------|--------------|
+| change  | 输入内容时触发 | val, event |
+| focus  | 聚焦时触发 | val, event |
+| blur  | 失焦时触发 | val, event |
+| clear  | 点击清空时触发 | val |
+| search  | 按下 ENTER 键时触发 | val, event |
+
+## Slots
+
+| 名称          | 说明                 |
+|---------------|----------------------|
+| leftin      | 输入框内 左icon  |
+| leftout     | 输入框外 左icon |
+| rightin     | 输入框内 右icon |
+| rightout    | 输入框外 右icon |

+ 92 - 0
src/packages/__VUE/searchbar/index.scss

@@ -0,0 +1,92 @@
+.nut-searchbar {
+  display: flex;
+  align-items: center;
+  .search-input {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    height: 32px;
+    flex: 1;
+    padding: 0 0 0 13px;
+    background-color: #fff;
+    border-radius: 16px;
+
+    .input-inner {
+      display: flex;
+      position: relative;
+      .input-clear {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        position: absolute;
+        z-index: 2;
+        top: 50%;
+        right: 0;
+        width: 16px;
+        height: 16px;
+        margin-top: -8px;
+        & .nut-icon-mask-close {
+          color: rgb(204, 204, 204);
+          &:hover {
+            cursor: pointer;
+            color: rgb(104, 104, 104);
+          }
+        }
+      }
+    }
+
+    .iptleft-search-icon {
+      margin-left: 12px;
+      margin-right: 6px;
+      width: 14px;
+      height: 14px;
+    }
+
+    .iptright-sarch-icon {
+    }
+
+    .input-bar {
+      width: 200px;
+      height: 32px;
+      flex: 1;
+      padding: 0;
+      margin: 0;
+      background-color: transparent;
+      border-color: transparent;
+      border-radius: 16px;
+      outline: none;
+      font-size: 14px;
+    }
+  }
+
+  .left-search-icon {
+    margin-right: 8px;
+  }
+
+  .search-icon {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+
+  .right-search-icon {
+    margin-left: 16px;
+  }
+
+  .btn-right {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-left: 12px;
+    font-size: 14px;
+    color: #e1251b;
+  }
+
+  a {
+    text-decoration: none;
+  }
+
+  .nut-icon {
+    vertical-align: middle;
+  }
+}

+ 149 - 0
src/packages/__VUE/searchbar/index.taro.vue

@@ -0,0 +1,149 @@
+<template>
+  <view class="nut-searchbar">
+    <view v-if="hasLeftOut" class="search-icon left-search-icon">
+      <slot name="leftout"></slot>
+    </view>
+    <view class="search-input">
+      <view v-if="hasLeftIn" class="search-icon iptleft-search-icon">
+        <slot name="leftin"></slot>
+      </view>
+      <view class="input-inner">
+        <input
+          class="input-bar"
+          :type="text"
+          :maxlength="maxLength"
+          :placeholder="placeholder"
+          :value="modelValue"
+          @input="valueChange"
+          @focus="valueFocus"
+          @blur="valueBlur"
+          @keypress="searchAction"
+        />
+        <view @click="handleClear" class="input-clear" v-if="clearable" v-show="modelValue.length > 0">
+          <nut-icon name="mask-close" size="12px"></nut-icon>
+        </view>
+      </view>
+      <view v-if="hasRightIn" class="search-icon iptright-sarch-icon">
+        <slot name="rightin"></slot>
+      </view>
+    </view>
+    <view v-if="hasRightIn" class="search-icon right-search-icon">
+      <slot name="rightout"></slot>
+    </view>
+  </view>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive } from 'vue';
+import { createComponent } from '../../utils/create';
+import Icon from '../icon/index.vue';
+const { create } = createComponent('searchbar');
+interface Events {
+  eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:modelValue';
+  params: (string | number | Event)[];
+}
+export default create({
+  props: {
+    modelValue: {
+      type: [String, Number],
+      default: ''
+    },
+    maxLength: {
+      type: [String, Number],
+      default: '9999'
+    },
+    placeholder: {
+      type: String,
+      default: '请输入'
+    },
+    clearable: {
+      type: Boolean,
+      default: true
+    },
+    hasLeftIn: {
+      type: Boolean,
+      default: true
+    },
+    hasLeftOut: {
+      type: Boolean,
+      default: true
+    },
+    hasRightIn: {
+      type: Boolean,
+      default: true
+    },
+    hasRightOut: {
+      type: Boolean,
+      default: true
+    }
+  },
+  components: {
+    [Icon.name]: Icon
+  },
+
+  emits: ['change', 'update:modelValue', 'blur', 'focus', 'clear', 'search'],
+
+  setup(props, { emit }) {
+    const {} = toRefs(props);
+
+    const state = reactive({
+      active: false
+    });
+
+    const valueChange = (event: Event) => {
+      const input = event.target as HTMLInputElement;
+      let val = input.value;
+
+      if (props.maxLength && val.length > Number(props.maxLength)) {
+        val = val.slice(0, Number(props.maxLength));
+      }
+      emit('update:modelValue', val, event);
+      emit('change', val, event);
+    };
+
+    const valueFocus = (event: Event) => {
+      const input = event.target as HTMLInputElement;
+      let value = input.value;
+      state.active = true;
+      emit('focus', value, event);
+    };
+
+    const searchAction = (event: any) => {
+      if (event.keyCode == 13) {
+        const input = event.target as HTMLInputElement;
+        let value = input.value;
+        state.active = true;
+        emit('search', value, event);
+      }
+    };
+
+    const valueBlur = (event: Event) => {
+      setTimeout(() => {
+        state.active = false;
+      }, 0);
+
+      const input = event.target as HTMLInputElement;
+      let value = input.value;
+      if (props.maxLength && value.length > Number(props.maxLength)) {
+        value = value.slice(0, Number(props.maxLength));
+      }
+      emit('blur', value, event);
+    };
+
+    const handleClear = (event: Event) => {
+      emit('update:modelValue', '', event);
+      emit('change', '', event);
+      emit('clear', '');
+    };
+
+    return {
+      ...toRefs(state),
+      valueChange,
+      valueFocus,
+      valueBlur,
+      handleClear,
+      searchAction
+    };
+  }
+});
+</script>

+ 149 - 0
src/packages/__VUE/searchbar/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <view class="nut-searchbar">
+    <view v-if="hasLeftOut" class="search-icon left-search-icon">
+      <slot name="leftout"></slot>
+    </view>
+    <view class="search-input">
+      <view v-if="hasLeftIn" class="search-icon iptleft-search-icon">
+        <slot name="leftin"></slot>
+      </view>
+      <view class="input-inner">
+        <input
+          class="input-bar"
+          :type="text"
+          :maxlength="maxLength"
+          :placeholder="placeholder"
+          :value="modelValue"
+          @input="valueChange"
+          @focus="valueFocus"
+          @blur="valueBlur"
+          @keypress="searchAction"
+        />
+        <view @click="handleClear" class="input-clear" v-if="clearable" v-show="modelValue.length > 0">
+          <nut-icon name="mask-close" size="12px"></nut-icon>
+        </view>
+      </view>
+      <view v-if="hasRightIn" class="search-icon iptright-sarch-icon">
+        <slot name="rightin"></slot>
+      </view>
+    </view>
+    <view v-if="hasRightIn" class="search-icon right-search-icon">
+      <slot name="rightout"></slot>
+    </view>
+  </view>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive } from 'vue';
+import { createComponent } from '../../utils/create';
+import Icon from '../icon/index.vue';
+const { create } = createComponent('searchbar');
+interface Events {
+  eventName: 'change' | 'focus' | 'blur' | 'clear' | 'update:modelValue';
+  params: (string | number | Event)[];
+}
+export default create({
+  props: {
+    modelValue: {
+      type: [String, Number],
+      default: ''
+    },
+    maxLength: {
+      type: [String, Number],
+      default: '9999'
+    },
+    placeholder: {
+      type: String,
+      default: '请输入'
+    },
+    clearable: {
+      type: Boolean,
+      default: true
+    },
+    hasLeftIn: {
+      type: Boolean,
+      default: true
+    },
+    hasLeftOut: {
+      type: Boolean,
+      default: true
+    },
+    hasRightIn: {
+      type: Boolean,
+      default: true
+    },
+    hasRightOut: {
+      type: Boolean,
+      default: true
+    }
+  },
+  components: {
+    [Icon.name]: Icon
+  },
+
+  emits: ['change', 'update:modelValue', 'blur', 'focus', 'clear', 'search'],
+
+  setup(props, { emit }) {
+    const {} = toRefs(props);
+
+    const state = reactive({
+      active: false
+    });
+
+    const valueChange = (event: Event) => {
+      const input = event.target as HTMLInputElement;
+      let val = input.value;
+
+      if (props.maxLength && val.length > Number(props.maxLength)) {
+        val = val.slice(0, Number(props.maxLength));
+      }
+      emit('update:modelValue', val, event);
+      emit('change', val, event);
+    };
+
+    const valueFocus = (event: Event) => {
+      const input = event.target as HTMLInputElement;
+      let value = input.value;
+      state.active = true;
+      emit('focus', value, event);
+    };
+
+    const searchAction = (event: any) => {
+      if (event.keyCode == 13) {
+        const input = event.target as HTMLInputElement;
+        let value = input.value;
+        state.active = true;
+        emit('search', value, event);
+      }
+    };
+
+    const valueBlur = (event: Event) => {
+      setTimeout(() => {
+        state.active = false;
+      }, 0);
+
+      const input = event.target as HTMLInputElement;
+      let value = input.value;
+      if (props.maxLength && value.length > Number(props.maxLength)) {
+        value = value.slice(0, Number(props.maxLength));
+      }
+      emit('blur', value, event);
+    };
+
+    const handleClear = (event: Event) => {
+      emit('update:modelValue', '', event);
+      emit('change', '', event);
+      emit('clear', '');
+    };
+
+    return {
+      ...toRefs(state),
+      valueChange,
+      valueFocus,
+      valueBlur,
+      handleClear,
+      searchAction
+    };
+  }
+});
+</script>

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

@@ -24,7 +24,8 @@ export default {
         'pages/steps/index',
         'pages/infiniteloading/index',
         'pages/progress/index',
-        'pages/circleprogress/index'
+        'pages/circleprogress/index',
+        'pages/searchbar/index'
       ]
     },
     {

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

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

+ 53 - 0
src/sites/mobile-taro/vue/src/feedback/pages/searchbar/index.vue

@@ -0,0 +1,53 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-searchbar class="wrap" v-model="searchValue" @search="search">
+      <template v-slot:leftout>
+        <nut-icon @click="clickLeft" size="20" name="left"></nut-icon>
+      </template>
+      <template v-slot:leftin>
+        <nut-icon size="14" name="search2"></nut-icon>
+      </template>
+      <template v-slot:rightin>
+        <nut-icon size="20" name="photograph"></nut-icon>
+      </template>
+      <template v-slot:rightout>
+        <nut-icon size="20" name="message"></nut-icon>
+      </template>
+    </nut-searchbar>
+  </div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive } from 'vue';
+
+export default {
+  props: {},
+  setup() {
+    const state = reactive({
+      searchValue: ''
+    });
+
+    const search = function () {
+      console.log('ENTER clicked');
+    };
+
+    const clickLeft = function () {
+      console.log('left clicked');
+    };
+
+    return {
+      clickLeft,
+      search,
+      ...toRefs(state)
+    };
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.wrap {
+  height: 80px;
+  background: rgba(0, 0, 0, 0.1);
+}
+</style>