浏览代码

feat: fixednav

richard1015 4 年之前
父节点
当前提交
8c971afa73

+ 12 - 1
src/config.json

@@ -213,7 +213,7 @@
           "name": "Swipe",
           "taro": true,
           "type": "component",
-          "cName": "滑动手势操作",
+          "cName": "滑动手势",
           "desc": "列表项左滑删除场景使用",
           "sort": 4,
           "show": true,
@@ -450,6 +450,17 @@
         },
         {
           "version": "3.0.0",
+          "name": "FixedNav",
+          "type": "component",
+          "cName": "悬浮导航",
+          "desc": "可拖拽的悬浮导航",
+          "taro": true,
+          "sort": 9,
+          "show": true,
+          "author": "richard1015"
+        },
+        {
+          "version": "3.0.0",
           "name": "Tab",
           "sort": 1,
           "cName": "标签组件",

+ 103 - 0
src/packages/__VUE/fixednav/demo.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="demo">
+    <nut-fixednav
+      active-text="基础用法"
+      :position="{ top: '70px' }"
+      v-model:visible="visible"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      type="left"
+      :position="{ top: '140px' }"
+      v-model:visible="visible1"
+      active-text="左侧收起"
+      un-active-text="左侧展开"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      :position="{ top: '210px' }"
+      :overlay="false"
+      v-model:visible="visible2"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      :position="{ top: '280px' }"
+      type="left"
+      v-model:visible="myActive"
+      @selected="selected"
+    >
+      <template v-slot:list>
+        <ul class="nut-fixednav__list">
+          <li class="nut-fixednav__list-item">1</li>
+          <li class="nut-fixednav__list-item">2</li>
+          <li class="nut-fixednav__list-item">3</li>
+          <li class="nut-fixednav__list-item">4</li>
+          <li class="nut-fixednav__list-item">5</li>
+        </ul>
+      </template>
+      <template v-slot:btn>
+        <nut-icon name="retweet" color="#fff"> </nut-icon>
+        <span class="text">{{ myActive ? '自定义开' : '自定义关' }}</span>
+      </template>
+    </nut-fixednav>
+  </div>
+</template>
+
+<script lang="ts">
+import { onMounted, reactive, ref } from 'vue';
+import { createComponent } from '../../utils/create';
+const { createDemo } = createComponent('fixednav');
+export default createDemo({
+  props: {},
+  setup() {
+    const visible = ref(false);
+    const visible1 = ref(false);
+    const visible2 = ref(false);
+    const myActive = ref(false);
+
+    onMounted(() => {
+      setTimeout(() => {
+        visible2.value = true;
+      }, 1000);
+    });
+
+    const navList = reactive([
+      {
+        id: 1,
+        text: '首页',
+        icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+      },
+      {
+        id: 2,
+        text: '分类',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+      },
+      {
+        id: 3,
+        text: '购物车',
+        num: 2,
+        icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+      },
+      {
+        id: 4,
+        text: '我的',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+      }
+    ]);
+    const selected = (res: any) => {
+      console.log(res);
+    };
+    return {
+      visible,
+      visible1,
+      visible2,
+      myActive,
+      navList,
+      selected
+    };
+  }
+});
+</script>

+ 156 - 0
src/packages/__VUE/fixednav/doc.md

@@ -0,0 +1,156 @@
+# FixedNav 悬浮导航
+
+### 介绍
+
+悬浮收齐体验交互,用于快捷导航
+
+### 安装
+    
+``` javascript
+import { createApp } from 'vue';
+// vue
+import { FixedNav,OverLay } from '@nutui/nutui';
+// taro
+import { FixedNav,OverLay } from '@nutui/nutui-taro';
+
+const app = createApp();
+app.use(FixedNav).use(OverLay);
+
+```
+
+
+### 基础用法
+
+``` html
+<nut-fixednav :position="{top:'70px' }" v-model:visible="visible" :nav-list="navList" />
+```
+``` javascript
+ setup() {
+    const visible = ref(false);
+    const navList = reactive([
+      {
+        id: 1,
+        text: '首页',
+        icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+      },
+      {
+        id: 2,
+        text: '分类',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+      },
+      {
+        id: 3,
+        text: '购物车',
+        num: 2,
+        icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+      },
+      {
+        id: 4,
+        text: '我的',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+      }
+    ]);
+    return {
+      visible,
+      navList
+    };
+ }
+```
+
+
+### 左侧效果
+
+``` html
+<nut-fixednav type="left" :position="{top:'140px' }" v-model:visible="visible" :nav-list="navList" />
+```
+
+
+### 取消背景遮罩
+
+``` html
+<nut-fixednav :overlay="false"  :position="{top:'210px' }" v-model:visible="visible" :nav-list="navList" />
+```
+
+
+### 自定义使用
+
+``` html
+<nut-fixednav :position="{top:'280px' }" type="left" v-model:visible="myActive">
+    <template v-slot:list>
+        <ul class="nut-fixednav__list">
+            <li class="nut-fixednav__list-item">1</li>
+            <li class="nut-fixednav__list-item">2</li>
+            <li class="nut-fixednav__list-item">3</li>
+            <li class="nut-fixednav__list-item">4</li>
+            <li class="nut-fixednav__list-item">5</li>
+        </ul>
+    </template>
+<template v-slot:btn>
+    <nut-icon name="retweet" color="#fff">
+    </nut-icon>
+    <span class="text">{{ myActive ? '自定义开' : '自定义关' }}</span>
+</template>
+</nut-fixednav>
+```
+
+``` javascript
+ setup() {
+    const myActive = ref(false);
+    const navList = reactive([
+      {
+        id: 1,
+        text: '首页',
+        icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+      },
+      {
+        id: 2,
+        text: '分类',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+      },
+      {
+        id: 3,
+        text: '购物车',
+        num: 2,
+        icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+      },
+      {
+        id: 4,
+        text: '我的',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+      }
+    ]);
+    return {
+      myActive,
+      navList
+    };
+ }
+```
+
+
+### Prop
+| 字段           | 说明                       | 类型    | 默认值                       |
+|:---------------|:---------------------------|:--------|:-----------------------------|
+| visible        | 是否打开                   | Boolean | false                        |
+| nav-list       | 悬浮列表内容数据           | Array   | []                           |
+| active-text    | 收起列表按钮文案           | String  | 收起导航                     |
+| un-active-text | 展开列表按钮文案           | String  | 快速导航                     |
+| type           | 导航方向,可选值 left right | String  | right                        |
+| overlay        | 展开时是否显示遮罩         | Boolean | true                         |
+| position       | fixed 垂直位置             | Object  | {top: 'auto',bottom: 'auto'} |
+
+
+### Event
+
+| 字段     | 说明         | 回调参数                 |
+|----------|--------------|--------------------------|
+| selected | 选择之后触发 | {item:item,$event:Event} |
+
+
+### Slot
+
+| 名称 | 说明               |
+|------|--------------------|
+| btn  | 自定义按钮         |
+| list | 自定义展开列表内容 |
+
+    

+ 129 - 0
src/packages/__VUE/fixednav/index.scss

@@ -0,0 +1,129 @@
+.nut-fixednav {
+  position: fixed;
+  z-index: $fixednav-index;
+  display: inline-block;
+  height: 50px;
+  right: 0;
+
+  &.active {
+    .nut-icon {
+      transform: rotate(180deg);
+    }
+    .nut-fixednav__list {
+      transform: translateX(0%) !important;
+    }
+    &.left {
+      .nut-icon {
+        transform: rotate(0deg) !important;
+      }
+    }
+  }
+
+  &__btn {
+    box-sizing: border-box;
+    position: absolute;
+    right: 0;
+
+    z-index: $fixednav-index + 1;
+    width: 80px;
+    padding-left: 12px;
+    height: 100%;
+    background: $fixednav-btn-bg;
+    border-radius: 45px 0px 0px 45px;
+    box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    > .text {
+      width: 24px;
+      line-height: 13px;
+      font-size: 10px;
+      color: $fixednav-bg-color;
+      flex-shrink: 0;
+    }
+    .nut-icon {
+      margin-right: 5px;
+      transition: all 0.3s;
+      transform: rotate(0deg);
+      transition: all 0.3s;
+    }
+  }
+
+  &__list {
+    position: absolute;
+    right: 0;
+    transform: translateX(100%);
+    transition: all 0.5s;
+
+    z-index: $fixednav-index;
+    flex-shrink: 0;
+    height: 100%;
+    background: $fixednav-bg-color;
+    display: flex;
+    justify-content: space-between;
+    border-radius: 25px 0px 0px 25px;
+    box-shadow: 2px 2px 8px 0px rgba(0, 0, 0, 0.2);
+    padding: {
+      left: 20px;
+      right: 80px;
+    }
+    &-item {
+      position: relative;
+      flex: 1;
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      min-width: 50px;
+      flex-shrink: 0;
+      > img {
+        width: 20px;
+        height: 20px;
+        margin-bottom: 2px;
+      }
+      > .span {
+        font-size: 10px;
+        color: $fixednav-font-color;
+      }
+      > .b {
+        position: absolute;
+        right: 0;
+        top: 1px;
+        height: 14px;
+        line-height: 14px;
+        font-size: 10px;
+        padding: 0 3px;
+        color: white;
+        background: $primary-color;
+        border-radius: 7px;
+        text-align: center;
+        min-width: 12px;
+      }
+    }
+  }
+  &.left {
+    right: auto;
+    left: 0;
+
+    .nut-fixednav__btn {
+      flex-direction: row-reverse;
+      right: auto;
+      left: 0;
+      border-radius: 0 45px 45px 0;
+      .nut-icon {
+        transform: rotate(180deg);
+      }
+    }
+    .nut-fixednav__list {
+      transform: translateX(-100%);
+      right: auto;
+      border-radius: 0px 25px 25px 0px;
+      padding: {
+        left: 80px;
+        right: 20px;
+      }
+    }
+  }
+}

+ 102 - 0
src/packages/__VUE/fixednav/index.taro.vue

@@ -0,0 +1,102 @@
+<template>
+  <view :class="classes" :style="position">
+    <nut-overlay
+      v-if="overlay"
+      :visible="visible"
+      :z-index="200"
+      @click="updateValue(false)"
+    />
+    <slot name="list">
+      <view class="nut-fixednav__list">
+        <view
+          class="nut-fixednav__list-item"
+          v-for="(item, index) in navList"
+          @click="selected(item, $event)"
+          :key="item.id || index"
+        >
+          <img :src="item.icon" />
+          <view class="span">{{ item.text }}</view>
+          <view class="b" v-if="item.num">{{ item.num }}</view>
+        </view>
+      </view>
+    </slot>
+    <div class="nut-fixednav__btn" @click="updateValue()">
+      <slot name="btn">
+        <nut-icon name="left" color="#fff" />
+        <view class="text">{{ visible ? activeText : unActiveText }}</view>
+      </slot>
+    </div>
+  </view>
+</template>
+<script lang="ts">
+import { computed } from 'vue';
+import { createComponent } from '../../utils/create';
+const { componentName, create } = createComponent('fixednav');
+
+export default create({
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    overlay: {
+      type: Boolean,
+      default: true
+    },
+    navList: {
+      default: () => [],
+      type: Array
+    },
+    activeText: {
+      default: '收起导航',
+      type: String
+    },
+    unActiveText: {
+      default: '快速导航',
+      type: String
+    },
+    position: {
+      default: () => {
+        return {
+          top: 'auto',
+          bottom: 'auto'
+        };
+      },
+      type: Object
+    },
+    type: {
+      default: 'right',
+      type: String
+    }
+  },
+  components: {},
+  emits: ['update:visible', 'selected'],
+
+  setup(props, { emit }) {
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      return {
+        [prefixCls]: true,
+        active: props.visible,
+        [props.type]: true
+      };
+    });
+
+    const updateValue = (value: boolean = !props.visible) => {
+      emit('update:visible', value);
+    };
+    const selected = (item: any, event: Event) => {
+      emit('selected', {
+        item,
+        event
+      });
+    };
+
+    return { classes, updateValue, selected };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 102 - 0
src/packages/__VUE/fixednav/index.vue

@@ -0,0 +1,102 @@
+<template>
+  <view :class="classes" :style="position">
+    <nut-overlay
+      v-if="overlay"
+      :visible="visible"
+      :z-index="200"
+      @click="updateValue(false)"
+    />
+    <slot name="list">
+      <view class="nut-fixednav__list">
+        <view
+          class="nut-fixednav__list-item"
+          v-for="(item, index) in navList"
+          @click="selected(item, $event)"
+          :key="item.id || index"
+        >
+          <img :src="item.icon" />
+          <view class="span">{{ item.text }}</view>
+          <view class="b" v-if="item.num">{{ item.num }}</view>
+        </view>
+      </view>
+    </slot>
+    <div class="nut-fixednav__btn" @click="updateValue()">
+      <slot name="btn">
+        <nut-icon name="left" color="#fff" />
+        <view class="text">{{ visible ? activeText : unActiveText }}</view>
+      </slot>
+    </div>
+  </view>
+</template>
+<script lang="ts">
+import { computed } from 'vue';
+import { createComponent } from '../../utils/create';
+const { componentName, create } = createComponent('fixednav');
+
+export default create({
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    overlay: {
+      type: Boolean,
+      default: true
+    },
+    navList: {
+      default: () => [],
+      type: Array
+    },
+    activeText: {
+      default: '收起导航',
+      type: String
+    },
+    unActiveText: {
+      default: '快速导航',
+      type: String
+    },
+    position: {
+      default: () => {
+        return {
+          top: 'auto',
+          bottom: 'auto'
+        };
+      },
+      type: Object
+    },
+    type: {
+      default: 'right',
+      type: String
+    }
+  },
+  components: {},
+  emits: ['update:visible', 'selected'],
+
+  setup(props, { emit }) {
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      return {
+        [prefixCls]: true,
+        active: props.visible,
+        [props.type]: true
+      };
+    });
+
+    const updateValue = (value: boolean = !props.visible) => {
+      emit('update:visible', value);
+    };
+    const selected = (item: any, event: Event) => {
+      emit('selected', {
+        item,
+        event
+      });
+    };
+
+    return { classes, updateValue, selected };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

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

@@ -1,4 +1,4 @@
-#  swipe组件
+#  Swipe 滑动手势
 
 ### 介绍
 

+ 10 - 0
src/packages/styles/variables.scss

@@ -267,5 +267,15 @@ $checkbox-label-disable-color: #999;
 $radio-label-color: #1d1e1e;
 $radio-label-disable-color: #999;
 
+//fixednav
+$fixednav-bg-color: $white;
+$fixednav-font-color: $black;
+$fixednav-index: 201;
+$fixednav-btn-bg: linear-gradient(
+  135deg,
+  rgba(250, 25, 44, 1) 0%,
+  rgba(250, 63, 25, 1) 100%
+);
+
 @import './mixins/index';
 @import './animation/index';

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

@@ -36,7 +36,12 @@ export default {
     },
     {
       root: 'nav',
-      pages: ['pages/navbar/index', 'pages/tabbar/index', 'pages/tab/index']
+      pages: [
+        'pages/navbar/index',
+        'pages/tabbar/index',
+        'pages/tab/index',
+        'pages/fixednav/index'
+      ]
     },
     {
       root: 'dentry',

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

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

+ 101 - 0
src/sites/mobile-taro/vue/src/nav/pages/fixednav/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="demo">
+    <nut-fixednav
+      active-text="基础用法"
+      :position="{ top: '70px' }"
+      v-model:visible="visible"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      type="left"
+      :position="{ top: '140px' }"
+      v-model:visible="visible1"
+      active-text="左侧收起"
+      un-active-text="左侧展开"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      :position="{ top: '210px' }"
+      :overlay="false"
+      v-model:visible="visible2"
+      :nav-list="navList"
+      @selected="selected"
+    />
+    <nut-fixednav
+      :position="{ top: '280px' }"
+      type="left"
+      v-model:visible="myActive"
+      @selected="selected"
+    >
+      <template v-slot:list>
+        <ul class="nut-fixednav__list">
+          <li class="nut-fixednav__list-item">1</li>
+          <li class="nut-fixednav__list-item">2</li>
+          <li class="nut-fixednav__list-item">3</li>
+          <li class="nut-fixednav__list-item">4</li>
+          <li class="nut-fixednav__list-item">5</li>
+        </ul>
+      </template>
+      <template v-slot:btn>
+        <nut-icon name="retweet" color="#fff"> </nut-icon>
+        <span class="text">{{ myActive ? '自定义开' : '自定义关' }}</span>
+      </template>
+    </nut-fixednav>
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, onMounted, reactive, ref } from 'vue';
+export default defineComponent({
+  props: {},
+  setup() {
+    const visible = ref(false);
+    const visible1 = ref(false);
+    const visible2 = ref(false);
+    const myActive = ref(false);
+
+    onMounted(() => {
+      setTimeout(() => {
+        visible2.value = true;
+      }, 1000);
+    });
+
+    const navList = reactive([
+      {
+        id: 1,
+        text: '首页',
+        icon: 'https://img11.360buyimg.com/imagetools/jfs/t1/117646/2/11112/1297/5ef83e95E81d77f05/daf8e3b1c81e3c98.png'
+      },
+      {
+        id: 2,
+        text: '分类',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/119490/8/9568/1798/5ef83e95E968c69a6/dd029326f7d5042e.png'
+      },
+      {
+        id: 3,
+        text: '购物车',
+        num: 2,
+        icon: 'https://img14.360buyimg.com/imagetools/jfs/t1/130725/4/3157/1704/5ef83e95Eb976644f/b36c6cfc1cc1a99d.png'
+      },
+      {
+        id: 4,
+        text: '我的',
+        icon: 'https://img12.360buyimg.com/imagetools/jfs/t1/147573/29/1603/1721/5ef83e94E1393a678/5ddf1695ec989373.png'
+      }
+    ]);
+    const selected = (res: any) => {
+      console.log(res);
+    };
+    return {
+      visible,
+      visible1,
+      visible2,
+      myActive,
+      navList,
+      selected
+    };
+  }
+});
+</script>