Browse Source

新增电梯楼层组件

zhenyulei 6 years ago
parent
commit
390058165f

+ 1 - 1
package.json

@@ -162,4 +162,4 @@
     "instrument": false,
     "instrument": false,
     "sourceMap": false
     "sourceMap": false
   }
   }
-}
+}

+ 10 - 0
src/config.json

@@ -482,6 +482,16 @@
       "sort": "1",
       "sort": "1",
       "showDemo": true,
       "showDemo": true,
       "author": "guoxiaoxiao"
       "author": "guoxiaoxiao"
+    },
+    {
+      "version": "1.0.0",
+      "name": "Elevator",
+      "chnName": "电梯楼层组件",
+      "desc": "类似于电梯楼层,组件可以跟着右侧索引而滑动",
+      "type": "component",
+      "sort": "3",
+      "showDemo": true,
+      "author": "zhenyulei"
     }
     }
   ]
   ]
 }
 }

+ 4 - 1
src/nutui.js

@@ -92,6 +92,8 @@ import "./packages/avatar/avatar.scss";
 import Lazyload from "./packages/lazyload/index.js";
 import Lazyload from "./packages/lazyload/index.js";
 import "./packages/textbox/textbox.scss";
 import "./packages/textbox/textbox.scss";
 import TextBox from "./packages/textbox/index.js";
 import TextBox from "./packages/textbox/index.js";
+import Elevator from "./packages/elevator/index.js";
+import "./packages/elevator/elevator.scss";
 
 
 const packages = {
 const packages = {
   Cell,
   Cell,
@@ -139,7 +141,7 @@ const packages = {
   TextInput,
   TextInput,
   TextBox,
   TextBox,
   Avatar,
   Avatar,
-  
+  Elevator: Elevator
 };
 };
 
 
 const components = {};
 const components = {};
@@ -149,6 +151,7 @@ const directives = {};
 pkgList.map(item => {
 pkgList.map(item => {
   const pkg = packages[item.name];
   const pkg = packages[item.name];
   if (!pkg) return;
   if (!pkg) return;
+
   if (item.type == 'component') {
   if (item.type == 'component') {
     if (pkg.name) {
     if (pkg.name) {
       components[pkg.name] = pkg;
       components[pkg.name] = pkg;

+ 239 - 0
src/packages/elevator/demo.vue

@@ -0,0 +1,239 @@
+<template>
+    <div>
+        <nut-elevator 
+        :dataArray="dataList"  
+        :showIndicator="true"
+        :navHeight="40"
+        :otherHeight="60"
+        :initIndex="0" 
+        :hiddenTime='500'
+        @clickNav="clickNav"
+        @clickList="clickList"
+        ></nut-elevator>
+  </div>
+</template>
+
+<script>
+export default {
+    data(){
+        return{
+          dataList:[
+            {
+              title:"A",
+              list:[
+                {
+                  name:'安其拉',
+                  id:'a1'
+                },
+                {
+                  name:'安琪',
+                  id:'a2'
+                }
+              ]
+            },
+            {
+              title:"B",
+              list:[
+                {
+                  name:'卞小明',
+                  id:'b1'
+                },
+                  {
+                  name:'卞小页',
+                  id:'b2'
+                }
+              ]
+            },
+            {
+              title:"C",
+              list:[
+                {
+                  name:'陈仙仙',
+                  id:'c1'
+                },
+                {
+                  name:'成小龙',
+                  id:'c2'
+                },
+                {
+                  name:'程野',
+                  id:'c3'
+                }
+              ]
+            },
+            {
+              title:"D",
+              list:[
+                {
+                  name:'丁小明',
+                  id:'d1'
+                },
+                {
+                  name:'丁小龙',
+                  id:'d2'
+                },
+                {
+                  name:'丁小野',
+                  id:'d3'
+                }
+              ]
+            },
+            {
+              title:"F",
+              list:[
+                {
+                  name:'冯小明',
+                  id:'f1'
+                },
+                {
+                  name:'冯小龙',
+                  id:'f2'
+                },
+                {
+                  name:'冯小野',
+                  id:'f3'
+                }
+              ]
+            },
+            {
+              title:"G",
+              list:[
+                {
+                  name:'高小明',
+                  id:'g1'
+                },
+                {
+                  name:'高小龙',
+                  id:'g2'
+                },
+                {
+                  name:'高小野',
+                  id:'g3'
+                },
+                {
+                  name:'高小阳',
+                  id:'g4'
+                },
+                {
+                  name:'郭小名',
+                  id:'g5'
+                }
+              ]
+            },
+            {
+              title:"H",
+              list:[
+                {
+                  name:'黄小明',
+                  id:'h1'
+                },
+                {
+                  name:'黄小龙',
+                  id:'h2'
+                },
+                {
+                  name:'黄小野',
+                  id:'h3'
+                },
+                {
+                  name:'郝小阳',
+                  id:'h4'
+                },
+                {
+                  name:'郝小名',
+                  id:'h5'
+                }
+              ]
+            },
+            {
+              title:"J",
+              list:[
+                {
+                  name:'贾小明',
+                  id:'j1'
+                },
+                {
+                  name:'贾小龙',
+                  id:'j2'
+                },
+                {
+                  name:'贾小野',
+                  id:'j3'
+                },
+                {
+                  name:'贾小阳',
+                  id:'j4'
+                },
+                {
+                  name:'贾小名',
+                  id:'j5'
+                }
+              ]
+            },
+            {
+              title:"K",
+              list:[
+                {
+                  name:'康小明',
+                  id:'k1'
+                },
+                {
+                  name:'康小龙',
+                  id:'k2'
+                },
+                {
+                  name:'康小野',
+                  id:'k3'
+                },
+                {
+                  name:'康小阳',
+                  id:'k4'
+                },
+                {
+                  name:'康小名',
+                  id:'k5'
+                }
+              ]
+            },
+            {
+              title:"L",
+              list:[
+                {
+                  name:'李小明',
+                  id:'l1'
+                },
+                {
+                  name:'李小龙',
+                  id:'l2'
+                },
+                {
+                  name:'李小野',
+                  id:'l3'
+                },
+                {
+                  name:'李小阳',
+                  id:'l4'
+                },
+                {
+                  name:'李小名',
+                  id:'l5'
+                }
+              ]
+            },
+          ]
+
+        }
+    },
+    methods:{
+      clickNav(title,index){
+        console.log(title,index);
+      },
+      clickList(list,item){
+        console.log(list,item);
+      }
+    }
+}
+</script>
+
+<style lang="scss">
+</style>

+ 53 - 0
src/packages/elevator/doc.md

@@ -0,0 +1,53 @@
+# Elevator 电梯楼层组件
+
+## 基本用法
+
+```html
+<nut-elevator 
+        :dataArray="dataList"  
+        :showIndicator="true"
+        :navHeight="0.8"
+        :initIndex="0" 
+        :hiddenTime='500'
+        @clickNav="clickNav"
+        @clickList="clickList"
+></nut-elevator>
+```
+数据类型
+```js
+dataList:[
+    {
+      title:"A",
+      list:[//可以为空数组
+        {
+          name:'安其拉',
+          id:'a1'//id字段可以没有
+        },
+        {
+          name:'安琪',
+          id:'a2'
+        }
+      ]
+    }    
+]
+```
+
+## Prop
+
+| 参数 | 说明 | 类型 | 默认值|可选值|
+|----- | ----- | ----- | ----- |---|
+| dataArray | 渲染楼层数据,为必填项 | Array | []| --|
+| showIndicator | 是否显示索引值提示符	 | Boolean | -- | --|
+| hiddenTime | 索引值提示符显示的时间,单位ms | Number | 500 | --|
+| navHeight | 索引栏每个索引区域的高度,单位rem | Number | 0.8 | --|
+| initIndex | 进入页面后,当前定位到的索引值 | Number | 0 | --|
+| otherHeight| 显示组件区域外部的高度,比如title区域高度,单位px|Number|40|--|
+
+## Events
+|事件名|说明|回调参数|
+|clickNav|点击/离开索引栏时的回调函数|返回点击的索引值和title|
+|clickList|点击左侧列表时的回调函数|返回点击的对象数据和所在区域的对象数据|
+
+
+
+

+ 62 - 0
src/packages/elevator/elevator.scss

@@ -0,0 +1,62 @@
+.nut-elevator{
+    overflow: scroll;
+    background:#FFF; 
+}
+.nut-elevator-ul{
+    width: 100%;
+    padding:0px;
+    margin:0px; 
+}
+.nut-list-title{
+    list-style-type:none;
+    width:100%;
+    margin-bottom:20px;
+}
+.nut-list-h{
+    height: 30px;
+    line-height: 30px;
+    padding-left: 20px;
+    background: #eee;
+    margin: 0px;
+}
+.nut-people-list{
+    padding: 0px;
+    padding-left: 20px;
+}
+.nut-list-name{
+    list-style-type:none;
+    height: 40px;
+    line-height: 40px;
+    border-bottom: 1px solid #ccc;
+}
+.nut-elevator-nav{
+    background: #fff;
+    text-align: center;
+    border:1px solid #ccc;
+    width: 50px;
+    position:fixed;
+    top:50%;
+    right: 0px;
+    transform:translate(0, -50%);
+    padding: 0px;
+    z-index: 100;
+    .nut-nav-list{
+        list-style-type:none;
+        height: 40px;
+        line-height: 40px;
+    }
+}
+.nut-big-box{
+    width: 26px;
+    height: 26px;
+    background: #000;
+    opacity: 0.7;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform:translate(-50%, -50%);
+    text-align: center;
+    line-height: 26px;
+    color:#fff;
+    font-family: bold;
+}

+ 156 - 0
src/packages/elevator/elevator.vue

@@ -0,0 +1,156 @@
+<template>
+    <div class="nut-elevator" id="nut-elevator" :style="{height:wrapHeight+'px'}">
+        <ul class="nut-elevator-ul" 
+            id="nut-elevator-ul"
+            >
+            <li 
+            v-for="item in dataArray" 
+            v-bind:key="item.title"
+            class="nut-list-title" 
+            >
+                <h3 class="nut-list-h" :id="item.title">{{item.title}}</h3>
+                <ul class="nut-people-list">
+                    <li v-for="(list,idx) in item.list" 
+                    v-bind:key="idx"
+                    class="nut-list-name" 
+                    :id="list.id?list.id:'list'+item.title+idx"
+                    @click="clickList(list,item)"
+                    >{{list.name}}</li>
+                </ul>
+            </li>
+        </ul>
+        <ul class="nut-elevator-nav" id="nut-elevator-nav" 
+            @touchmove="onPointerMove($event)"
+            @touchstart="onPointerMove($event)"
+            @touchend="onPointerEnd($event)"
+            >
+            <li v-for="(item,index) in dataArray"
+            v-bind:key="index" 
+            :id="'nav'+index"
+            class="nut-nav-list" 
+            :style="{height:navListHeight+'px'}"
+            @click="clickNav(item.title,index)"
+            >{{item.title}}</li>
+        </ul>
+        <template v-if="showIndicator">
+            <div class="nut-big-box" v-show="currBox">
+                {{currTitle}}
+            </div>
+        </template>
+    </div>
+</template>
+<script>
+export default {
+    name:'nut-elevator',
+    props: {
+        'otherHeight':{
+            type:Number,
+            default:'60',
+        },
+        'dataArray':{
+            type:Array,
+            required:true,
+        },
+        'navHeight':{
+            type:Number,
+            default:'40',
+        },
+        'hiddenTime':{
+            type:Number,
+            default:'10',
+        },
+        'showIndicator':{
+            type:Boolean,
+            default:true,
+        },
+        'initIndex':{
+            type:Number,
+            default:'0',
+        }
+    },
+    computed:{
+        navListHeight:function(){
+            return this.navHeight;
+        }
+    },
+    data() {
+        return {
+            wrapHeight:'40',
+            currTitle:'',
+            currBox:false,
+        };
+    },
+    mounted(){
+        this.initPage();
+    },
+    methods: {
+        initPage(){
+            let fontSize = this.getFontSize();
+            let innerHeight = document.documentElement.clientHeight;
+            //this.wrapHeight = (innerHeight/fontSize-1);
+            this.wrapHeight = innerHeight-this.otherHeight;
+            let initIndex = this.dataArray[this.initIndex].title; 
+            document.getElementById(initIndex).scrollIntoView();
+        },
+        getStyle(element, attr) {
+            if(element.currentStyle) {
+                    return element.currentStyle[attr];
+            } else {
+                    return getComputedStyle(element, false)[attr];
+            }
+        },
+        getFontSize(){
+            let htmlDom = document.getElementsByTagName('html')[0];
+            let bili = this.getStyle(htmlDom,'fontSize');
+            return bili.substring(0,bili.length-2);
+        },
+        clickNav(title,index){
+            this.currBox =true;
+            setTimeout(()=>{
+                this.currBox =false;
+            },this.hiddenTime);
+            this.moveFun(title,index);
+        },
+        clickList(list,item){
+            this.$emit('clickList',list,item);  
+        },
+        moveFun(title,index){
+            let titleBox = document.getElementById(title);
+            titleBox.scrollIntoView();
+        },
+        onPointerEnd(e){
+            let fontSize = this.getFontSize();
+            let dataArrayLength = this.dataArray.length;
+            let navHeight = document.getElementById('nut-elevator-nav').clientHeight;
+            let navTop = document.getElementById('nut-elevator-nav').offsetTop;
+            let navOffsetTop=navTop-navHeight/2 //nav距离顶部的距离
+            let eTop = e.type.indexOf('touch') !== -1 ? e.changedTouches[0].clientY : e.clientY;
+            //let navIndex =parseInt((eTop - navOffsetTop)/this.navHeight/fontSize);
+            let navIndex =parseInt((eTop - navOffsetTop)/this.navHeight);
+            setTimeout(()=>{
+                this.currBox = false;
+            },this.hiddenTime);
+            if(navIndex<dataArrayLength && navIndex>=0){
+            this.$emit('clickNav',this.dataArray[navIndex].title,navIndex);                 
+            }
+        },
+        onPointerMove(e){
+            e.preventDefault();
+            let fontSize = this.getFontSize();
+            let dataArrayLength = this.dataArray.length;
+            let navHeight = document.getElementById('nut-elevator-nav').clientHeight;
+            let navTop = document.getElementById('nut-elevator-nav').offsetTop;
+            let navOffsetTop=navTop-navHeight/2 //nav距离顶部的距离
+            let eTop = e.type.indexOf('touch') !== -1 ? e.touches[0].clientY : e.clientY;
+            //let navIndex =parseInt((eTop - navOffsetTop)/this.navHeight/fontSize);
+            let navIndex =parseInt((eTop - navOffsetTop)/this.navHeight);
+
+            if(navIndex<dataArrayLength && navIndex>=0){
+                this.moveFun(this.dataArray[navIndex].title,navIndex);
+                this.currBox =true;
+                this.currTitle = this.dataArray[navIndex].title;
+            }
+        },
+    }
+}
+</script>

+ 8 - 0
src/packages/elevator/index.js

@@ -0,0 +1,8 @@
+import Elevator from './elevator.vue';
+import './elevator.scss';
+
+Elevator.install = function(Vue) {
+  Vue.component(Elevator.name, Elevator);
+};
+
+export default Elevator

+ 1 - 0
types/nutui.d.ts

@@ -63,3 +63,4 @@ export declare class TextInput extends UIComponent {}
 export declare class Avatar extends UIComponent {}
 export declare class Avatar extends UIComponent {}
 export declare class Infiniteloading extends UIComponent {}
 export declare class Infiniteloading extends UIComponent {}
 export declare class Lazyload extends UIComponent {}
 export declare class Lazyload extends UIComponent {}
+export declare class Elevator extends UIComponent {}