浏览代码

Merge pull request #3 from jdf2e/v2-dev

upd
zjyau 5 年之前
父节点
当前提交
15d52d7ea0

+ 48 - 0
src/mixins/touch.js

@@ -0,0 +1,48 @@
+import Vue from "vue";
+
+const MIN_DISTANCE = 10;
+
+function getDirection(x, y) {
+  if (x > y && x > MIN_DISTANCE) {
+    return "horizontal";
+  }
+
+  if (y > x && y > MIN_DISTANCE) {
+    return "vertical";
+  }
+
+  return "";
+}
+
+const TouchMixin = Vue.extend({
+  data() {
+    return { direction: "" };
+  },
+
+  methods: {
+    touchStart(event) {
+      this.resetTouchStatus();
+      this.startX = event.touches[0].clientX;
+      this.startY = event.touches[0].clientY;
+    },
+
+    touchMove(event) {
+      const touch = event.touches[0];
+      this.deltaX = touch.clientX - this.startX;
+      this.deltaY = touch.clientY - this.startY;
+      this.offsetX = Math.abs(this.deltaX);
+      this.offsetY = Math.abs(this.deltaY);
+      this.direction =
+        this.direction || getDirection(this.offsetX, this.offsetY);
+    },
+
+    resetTouchStatus() {
+      this.direction = "";
+      this.deltaX = 0;
+      this.deltaY = 0;
+      this.offsetX = 0;
+      this.offsetY = 0;
+    },
+  },
+});
+export default TouchMixin;

+ 1 - 1
src/packages/popup/__test__/popup.spec.js

@@ -1,7 +1,7 @@
 import { mount } from '@vue/test-utils'
 import popup from '../popup.vue'
 import Vue from 'vue';
-import overlay from "../overlay.vue";
+// import overlay from "../overlay.vue";
 import Icon from '../../icon/icon.vue';
 describe('Menu.vue',() => {
     const wrapper = mount(popup, {

+ 116 - 22
src/packages/popup/demo.vue

@@ -2,43 +2,137 @@
   <div>
     <h2 class="title">基本用法</h2>
     <div>
-      <nut-cell isLink title="展示弹出层" :showIcon="true" @click.native="showBasic = true"> </nut-cell>
+        <nut-cell
+        isLink
+        title="展示弹出层"
+        :showIcon="true"
+        @click.native="showBasic = true"
+        >
+        </nut-cell>
     </div>
-    <nut-popup :style="{ padding: '30px 50px' }" v-model="showBasic">正文</nut-popup>
+    <nut-popup :style="{ padding: '30px 50px' }"   v-model="showBasic" >正文</nut-popup>
 
     <h2 class="title">弹出位置</h2>
     <div>
-      <nut-cell isLink title="顶部弹出" :showIcon="true" @click.native="showTop = true"> </nut-cell>
-      <nut-popup position="top" v-model="showTop" :style="{ height: '20%' }"> </nut-popup>
-      <nut-cell isLink title="底部弹出" :showIcon="true" @click.native="showBottom = true"> </nut-cell>
-      <nut-popup v-model="showBottom" position="bottom" :style="{ height: '20%' }"> </nut-popup>
-      <nut-cell isLink title="左侧弹出" :showIcon="true" @click.native="showLeft = true"> </nut-cell>
-      <nut-popup :style="{ width: '20%', height: '100%' }" v-model="showLeft" position="left"></nut-popup>
-      <nut-cell isLink title="右侧弹出" :showIcon="true" @click.native="showRight = true"> </nut-cell>
-      <nut-popup position="right" v-model="showRight" :style="{ width: '20%', height: '100%' }"></nut-popup>
+        <nut-cell
+        isLink
+        title="顶部弹出"
+        :showIcon="true"
+        @click.native="showTop = true"
+        >
+        </nut-cell>
+        <nut-popup position="top" v-model="showTop" :style="{ height: '20%' }">
+        </nut-popup>
+        <nut-cell
+        isLink
+        title="底部弹出"
+        :showIcon="true"
+        @click.native="showBottom = true"
+        >
+        </nut-cell>
+        <nut-popup
+        v-model="showBottom"
+        position="bottom"
+        :style="{ height: '20%' }"
+        >
+        </nut-popup>
+        <nut-cell
+        isLink
+        title="左侧弹出"
+        :showIcon="true"
+        @click.native="showLeft = true"
+        >
+        </nut-cell>
+        <nut-popup
+        :style="{ width: '20%', height: '100%' }"
+        v-model="showLeft"
+        position="left"
+        ></nut-popup>
+        <nut-cell
+        isLink
+        title="右侧弹出"
+        :showIcon="true"
+        @click.native="showRight = true"
+        >
+        </nut-cell>
+        <nut-popup
+        position="right"
+        v-model="showRight"
+        :style="{ width: '20%', height: '100%' }"
+        ></nut-popup>
     </div>
     <h2 class="title">关闭图标</h2>
     <div>
-      <nut-cell isLink title="关闭图标" :showIcon="true" @click.native="showIcon = true"> </nut-cell>
-      <nut-popup position="bottom" closeable v-model="showIcon" :style="{ height: '20%' }"></nut-popup>
+        <nut-cell
+        isLink
+        title="关闭图标"
+        :showIcon="true"
+        @click.native="showIcon = true">
+        </nut-cell>
+        <nut-popup
+        position="bottom"
+        closeable 
+        v-model="showIcon"
+        :style="{ height: '20%' }"
+        ></nut-popup>
 
-      <nut-cell isLink title="图标位置" :showIcon="true" @click.native="showIconPosition = true"> </nut-cell>
-      <nut-popup position="bottom" closeable close-icon-position="top-left" v-model="showIconPosition" :style="{ height: '20%' }"></nut-popup>
+        <nut-cell
+        isLink
+        title="图标位置"
+        :showIcon="true"
+        @click.native="showIconPosition = true">
+        </nut-cell>
+        <nut-popup
+        position="bottom"
+        closeable 
+        close-icon-position="top-left"
+        v-model="showIconPosition"
+        :style="{ height: '20%' }"
+        ></nut-popup>
 
-      <nut-cell isLink title="自定义图标" :showIcon="true" @click.native="showCloseIcon = true"> </nut-cell>
-      <nut-popup position="bottom" closeable close-icon="tick" v-model="showCloseIcon" :style="{ height: '20%' }"></nut-popup>
+
+        <nut-cell
+        isLink
+        title="自定义图标"
+        :showIcon="true"
+        @click.native="showCloseIcon = true">
+        </nut-cell>
+        <nut-popup
+        position="bottom"
+        closeable 
+        close-icon="tick"
+        v-model="showCloseIcon"
+        :style="{ height: '20%' }"
+        ></nut-popup>
     </div>
 
     <h2 class="title">圆角弹框</h2>
     <div>
-      <nut-cell isLink title="圆角弹框" :showIcon="true" @click.native="showRound = true"> </nut-cell>
-      <nut-popup round v-model="showRound" position="bottom" :style="{ height: '20%' }"></nut-popup>
+        <nut-cell
+        isLink
+        title="圆角弹框"
+        :showIcon="true"
+        @click.native="showRound = true"
+        >
+        </nut-cell>
+        <nut-popup
+        round
+        v-model="showRound"
+        position="bottom"
+        :style="{ height: '20%' }"
+        ></nut-popup>
     </div>
     <h2 class="title">指定挂载节点</h2>
     <div>
-      <nut-cell isLink title="指定挂载节点" :showIcon="true" @click.native="getContainer = true"> </nut-cell>
+        <nut-cell
+        isLink
+        title="指定挂载节点"
+        :showIcon="true"
+        @click.native="getContainer = true"
+        >
+        </nut-cell>
     </div>
-    <nut-popup :style="{ padding: '30px 50px' }" get-container="body" v-model="getContainer">body</nut-popup>
+    <nut-popup :style="{ padding: '30px 50px' }"  get-container="body"  v-model="getContainer" >body</nut-popup>
   </div>
 </template>
 <script>
@@ -55,10 +149,10 @@ export default {
       showRound: false,
       showIconPosition: false,
       showCloseIcon: false,
-      getContainer: false
+      getContainer:false
     };
   },
-  methods: {
+  methods: {     
     show() {
       this.isShow = true;
     }

+ 4 - 2
src/packages/popup/index.js

@@ -1,8 +1,10 @@
-import Popup from './popup.vue';
-import './popup.scss';
+import Popup from "./popup.vue";
+import "./popup.scss";
+import { overlayProps ,getProps} from "./overlay/overlay-manager";
 
 Popup.install = function(Vue) {
   Vue.component(Popup.name, Popup);
 };
 
 export default Popup;
+export {overlayProps, getProps};

+ 0 - 31
src/packages/popup/overlay.vue

@@ -1,31 +0,0 @@
-<template>
-  <transition name="popup-fade">
-    <div
-      @touchmove.stop="touchmove"
-      :style="{ animationDuration: `${duration}s`, customStyle }"
-      v-show="show"
-      class="popup-bg nut-mask"
-      :class="className"
-    ></div>
-  </transition>
-</template>
-<script>
-export default {
-  name: 'nut-popup-mask',
-
-  props: {
-    lockScroll: { type: Boolean, default: true },
-    show: { type: Boolean, default: false },
-    duration: Number,
-    className: { type: String, default: '' },
-    customStyle: { type: String, default: '' }
-  },
-  methods: {
-    touchmove(e) {
-      if (this.lockScroll) {
-        e.preventDefault();
-      }
-    }
-  }
-};
-</script>

+ 144 - 0
src/packages/popup/overlay/overlay-manager.js

@@ -0,0 +1,144 @@
+import Vue from "vue";
+import overlayComponent from "./overlay.vue";
+
+let modalStack = [];
+let _zIndex = 2000;
+
+const overlayManager = {
+  overlay: null,
+
+  lockCount: 0,
+
+  get zIndex() {
+    return ++_zIndex;
+  },
+  get topStack() {
+    return modalStack[modalStack.length - 1];
+  },
+
+  updateOverlay() {
+    const { overlay, clickHandle, topStack } = overlayManager;
+    if (!overlay) {
+      overlayManager.overlay = mount(overlayComponent, {
+        nativeOn: {
+          click: clickHandle,
+        },
+      });
+    }
+
+    if (topStack) {
+      const { vm, config } = topStack;
+      const el = vm.$el;
+      el && el.parentNode && el.parentNode.nodeType !== 11
+        ? el.parentNode.appendChild(overlay.$el)
+        : document.body.appendChild(overlay.$el);
+
+      Object.assign(overlayManager.overlay, config, {
+        value: true,
+      });
+    } else {
+      overlayManager.overlay.value = false;
+    }
+  },
+
+  //打开遮罩层
+  openModal(vm, config) {
+    let { zIndex, duration, className, customStyle } = config;
+
+    overlayManager.updateOverlay();
+
+    modalStack.push({
+      vm,
+      config: {
+        zIndex,
+        duration,
+        className,
+        customStyle,
+      },
+    });
+
+    overlayManager.updateOverlay();
+  },
+
+  clickHandle() {
+    const { topStack } = overlayManager;
+    
+    //防止多次点击
+    if (modalStack.length && topStack.vm.closeOnClickOverlay) { 
+      topStack.vm.$emit("click-overlay");
+      topStack.vm.close();
+  
+    }
+  },
+
+  closeOverlay(vm) {
+    if (modalStack.length) {
+      if (overlayManager.topStack.vm === vm) {
+        modalStack.pop();
+        overlayManager.updateOverlay();
+      } else {
+        modalStack = modalStack.filter((item) => item.vm !== vm);
+      }
+    }
+  },
+};
+
+const overlayProps = {
+  value: {
+    type: Boolean,
+    default: false,
+  },
+  overlay: {
+    type: Boolean,
+    default: true,
+  },
+  lockScroll: {
+    type: Boolean,
+    default: true,
+  },
+  duration: {
+    type: Number,
+    default: 0.3,
+  },
+  closeOnClickOverlay: {
+    type: Boolean,
+    default: true,
+  },
+  overlayClass: {
+    type: String,
+    default: "",
+  },
+  overlayStyle: {
+    type: String,
+    default: "",
+  },
+  zIndex: {
+    type: Number
+  },
+};
+
+function mount(Component, data) {
+  const instance = new Vue({
+    el: document.createElement("div"),
+    props: Component.props,
+    render(h) {
+      return h(Component, {
+        props: this.$props,
+        ...data,
+      });
+    },
+  });
+  return instance;
+}
+
+function getProps(){
+  
+  if(!this)return {}
+  let obj = {};
+    Object.keys(overlayProps).forEach(res=>{
+        obj[res] = this[res]
+  }) 
+  return obj
+}
+
+export  {overlayManager ,overlayProps, getProps};

+ 58 - 0
src/packages/popup/overlay/overlay.vue

@@ -0,0 +1,58 @@
+<template>
+  <transition name="popup-fade">
+    <div
+      @touchmove.stop="touchmove"
+      :style="{ animationDuration: `${duration}s`, overlayStyle, zIndex }"
+      v-show="value"
+      class="popup-bg nut-mask"
+      :class="overlayClass"
+    ></div>
+  </transition>
+</template>
+<script>
+const overlayProps = {
+  value: {
+    type: Boolean,
+    default: false,
+  },
+  overlay: {
+    type: Boolean,
+    default: true,
+  },
+  lockScroll: {
+    type: Boolean,
+    default: true,
+  },
+  duration: {
+    type: Number,
+    default: 0.3,
+  },
+  closeOnClickOverlay: {
+    type: Boolean,
+    default: true,
+  },
+  overlayClass: {
+    type: String,
+    default: "",
+  },
+  overlayStyle: {
+    type: String,
+    default: "",
+  },
+  zIndex: {
+    type: Number
+  },
+};
+export { overlayProps };
+export default {
+  name: "nut-popup-overlay",
+  props: overlayProps,
+  methods: {
+    touchmove(e) {
+      if (this.lockScroll) {
+        e.preventDefault();
+      }
+    },
+  },
+};
+</script>

+ 139 - 109
src/packages/popup/popup.vue

@@ -1,5 +1,9 @@
 <template>
-  <transition :name="transitionName" @after-enter="$emit('opened')" @after-leave="$emit('closed')">
+  <transition
+    :name="transitionName"
+    @after-enter="$emit('opened')"
+    @after-leave="$emit('closed')"
+  >
     <div
       ref="popupBox"
       v-show="value"
@@ -22,176 +26,202 @@
   </transition>
 </template>
 <script>
-import Vue from 'vue';
-import overlay from './overlay.vue';
-import Icon from '../icon/icon.vue';
-import '../icon/icon.scss';
+import Vue from "vue";
+import Icon from "../icon/icon.vue";
+import touchMixins from "../../mixins/touch.js";
+import {overlayManager ,overlayProps} from "./overlay/overlay-manager.js";
+import { on, off } from "../../utils/event"; 
+import "../icon/icon.scss";
+
+
+const overflowScrollReg = /scroll|auto/i;
 export default {
-  name: 'nut-popup',
+  name: "nut-popup",
+  mixins: [touchMixins],
   components: {
-    icon: Icon
+    icon: Icon,
   },
   props: {
-    value: {
-      type: Boolean,
-      default: false
-    },
+    ...overlayProps,
     position: {
       type: String,
-      default: 'center'
-    },
-    duration: {
-      type: Number,
-      default: 0.3
+      default: "center",
     },
+
     transition: String,
-    overlay: {
-      type: Boolean,
-      default: true
-    },
+
     closeable: {
       type: Boolean,
-      default: false
+      default: false,
     },
     closeIconPosition: {
       type: String,
-      default: 'top-right'
+      default: "top-right",
     },
     closeIcon: {
       type: String,
-      default: 'cross'
-    },
-    lockScroll: {
-      type: Boolean,
-      default: true
+      default: "cross",
     },
+
     closeOnClickOverlay: {
       type: Boolean,
-      default: true
-    },
-    overlayClass: {
-      type: String,
-      default: ''
-    },
-    overlayStyle: {
-      type: String,
-      default: ''
+      default: true,
     },
+
     destroyOnClose: {
       type: Boolean,
-      default: false
+      default: false,
     },
     getContainer: String,
     round: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   created() {
-    this.transition ? (this.transitionName = this.transition) : (this.transitionName = `popup-slide-${this.position}`);
+    this.transition
+      ? (this.transitionName = this.transition)
+      : (this.transitionName = `popup-slide-${this.position}`);
   },
   mounted() {
-    this.mountOverlay();
-    if (this.getContainer) {
-      this.portal();
-    }
     if (this.value) {
       this.open();
     }
   },
   watch: {
     value(val) {
-      const type = val ? 'open' : 'close';
-      if (this.overlay) {
-        this[type]();
-      }
+      const type = val ? "open" : "close";
+      this[type]();
     },
     position(val) {
-      val === 'center' ? (this.transitionName = 'popup-fade') : (this.transitionName = `popup-slide-${this.position}`);
+      val === "center"
+        ? (this.transitionName = "popup-fade")
+        : (this.transitionName = `popup-slide-${this.position}`);
     },
-    getContainer: 'portal'
+    getContainer: "portal",
+    overlay: "renderOverlay",
   },
   data() {
     return {
       showSlot: true,
-      transitionName: 'popup-fade-center',
-      overlayInstant: null
+      transitionName: "popup-fade-center",
+      overlayInstant: null,
     };
   },
   computed: {
     transitionDuration() {
-      return this.duration ? this.duration + 's' : 'initial';
-    }
+      return this.duration ? this.duration + "s" : "initial";
+    },
   },
   methods: {
-    mountOverlay() {
-      if (!this.overlayInstant) {
-        this.overlayInstant = this.mount(overlay, {
-          duration: this.duration,
-          nativeOn: {
-            click: () => {
-              this.$emit('click-overlay', this);
-              if (this.closeOnClickOverlay) {
-                this.$emit('input', false);
-              }
-            }
-          }
-        });
+    open() {
+      if (this.opened) {
+        return;
       }
-    },
-    mount(Component, data) {
-      const instance = new Vue({
-        el: document.createElement('div'),
-        props: Component.props,
-        render(h) {
-          return h(Component, {
-            props: this.$props,
-            ...data
-          });
+
+      this.opened = true;
+      this.$emit("open");
+   
+      const {
+        duration,
+        overlayClass,
+        overlayStyle,
+        lockScroll,
+        closeOnClickOverlay,
+      } = this; 
+      const config = {
+        zIndex:this.zIndex ? this.zIndex : overlayManager.zIndex,
+        duration,
+        overlayClass,
+        overlayStyle,
+        lockScroll,
+        closeOnClickOverlay,
+      };
+
+      this.renderOverlay(config);
+
+      if (this.lockScroll) {
+        on(document, "touchstart", this.touchStart);
+        on(document, "touchmove", this.onTouchMove);
+
+        if (!overlayManager.lockCount) {
+          document.body.classList.add("nut-overflow-hidden");
         }
-      });
-      instance.duration = this.duration;
-      instance.lockScroll = this.lockScroll;
-      instance.className = this.overlayClass;
-      instance.customStyle = this.overlayStyle;
-      const el = this.$refs.popupBox;
-      if (el && el.parentNode) {
-        el.parentNode.insertBefore(instance.$el, el);
-      } else {
-        document.body.appendChild(instance.$el);
+        overlayManager.lockCount++;
       }
-      return instance;
+      
+      this.$el.style.zIndex = this.zIndex ? this.zIndex + 1 : overlayManager.zIndex;
     },
+    renderOverlay(config) {
+      if (!this.value) {
+        return;
+      }
 
-    open() {
-      if (!this.overlayInstant) {
-        this.mountOverlay();
+      if (this.overlay) {
+        overlayManager.openModal(this, config);
       } else {
-        this.overlayInstant.show = true;
-        this.showSlot = true;
+        overlayManager.closeOverlay(this);
       }
+    },
+    onTouchMove(event) {
+      this.touchMove(event);
+      const el = this.getScroller(event.target, this.$el);
+      const { scrollHeight, offsetHeight, scrollTop } = el;
 
-      if (this.lockScroll && !this.locked) {
-        document.body.classList.add('nut-overflow-hidden');
-        this.locked = true;
+      if (
+        (this.deltaY > 0 && scrollTop === 0) ||
+        (this.deltaY < 0 && scrollTop + offsetHeight >= scrollHeight)
+      ) {
+        event.preventDefault();
       }
+    },
+    getScroller(el, root) {
+      let node = el;
+      while (
+        node &&
+        node.tagName !== "HTML" &&
+        node.nodeType === 1 &&
+        node !== root
+      ) {
+        const { overflowY } = window.getComputedStyle(node);
+
+        if (overflowScrollReg.test(overflowY)) {
+          if (node.tagName !== "BODY") {
+            return node;
+          }
+          const { overflowY: htmlOverflowY } = window.getComputedStyle(
+            node.parentNode
+          );
 
-      this.$emit('open', this);
+          if (overflowScrollReg.test(htmlOverflowY)) {
+            return node;
+          }
+        }
+
+        node = node.parentNode;
+      }
+
+      return root;
     },
     close() {
-      this.overlayInstant.show = false;
-      if (this.destroyOnClose) {
-        setTimeout(() => {
-          this.showSlot = false;
-        }, this.duration * 1000);
+      if (!this.opened) {
+        return;
       }
-
-      if (this.lockScroll && this.locked) {
-        document.body.classList.remove('nut-overflow-hidden');
-        this.locked = false;
+      this.$emit('close')
+      this.opened = false;
+      if (this.lockScroll) {
+        overlayManager.lockCount--;
+        off(document, "touchstart", this.touchStart);
+        off(document, "touchmove", this.onTouchMove);
+        if (!overlayManager.lockCount) {
+          document.body.classList.remove("nut-overflow-hidden");
+        }
       }
-      this.$emit('close', this);
+
+      overlayManager.closeOverlay(this);
+      this.$emit("input", false);
     },
+
     getElement(selector) {
       return document.querySelector(selector);
     },
@@ -209,7 +239,7 @@ export default {
       if (container && container !== el.parentNode) {
         container.appendChild(el);
       }
-    }
-  }
+    },
+  },
 };
 </script>

+ 10 - 8
src/packages/sidenavbar/demo.vue

@@ -9,14 +9,16 @@
       </nut-cell>
       <nut-popup position="right" v-model="show1" :style="{ width, height }">
         <nut-sidenavbar :show="show1">
-          <nut-subsidenavbar title="图像理解" ikey="3" :open="false">
-            <nut-sidenavbaritem ikey="4" title="菜品识别"></nut-sidenavbaritem>
-            <nut-sidenavbaritem ikey="5" title="拍照购"></nut-sidenavbaritem>
-          </nut-subsidenavbar>
-          <nut-subsidenavbar title="自然语言处理" ikey="12">
-            <nut-sidenavbaritem ikey="13" title="词法分析"></nut-sidenavbaritem>
-            <nut-sidenavbaritem ikey="14" title="句法分析"></nut-sidenavbaritem>
-          </nut-subsidenavbar>
+            <nut-subsidenavbar title="智能城市AI" ikey="6">
+                <nut-subsidenavbar title="人体识别1" ikey="9">
+                    <nut-sidenavbaritem ikey="10" title="人体检测1"></nut-sidenavbaritem>
+                    <nut-sidenavbaritem ikey="11" title="细粒度人像分割1"></nut-sidenavbaritem>
+                </nut-subsidenavbar>
+                <nut-subsidenavbar title="人体识别2" ikey="12">
+                    <nut-sidenavbaritem ikey="13" title="人体检测2"></nut-sidenavbaritem>
+                    <nut-sidenavbaritem ikey="14" title="细粒度人像分割2"></nut-sidenavbaritem>
+                </nut-subsidenavbar>
+            </nut-subsidenavbar>
         </nut-sidenavbar>
       </nut-popup>
     </div>

+ 9 - 7
src/packages/sidenavbar/doc.md

@@ -11,13 +11,15 @@
     :style="{ width, height }"
 >
     <nut-sidenavbar :show="show1">
-        <nut-subsidenavbar title="图像理解" ikey="3" :open="false">
-            <nut-sidenavbaritem ikey="4" title="菜品识别"></nut-sidenavbaritem>
-            <nut-sidenavbaritem ikey="5" title="拍照购"></nut-sidenavbaritem>
-        </nut-subsidenavbar>
-        <nut-subsidenavbar title="自然语言处理" ikey="12">
-            <nut-sidenavbaritem ikey="13" title="词法分析"></nut-sidenavbaritem>
-            <nut-sidenavbaritem ikey="14" title="句法分析"></nut-sidenavbaritem>
+        <nut-subsidenavbar title="智能城市AI" ikey="6">
+            <nut-subsidenavbar title="人体识别1" ikey="9">
+                <nut-sidenavbaritem ikey="10" title="人体检测1"></nut-sidenavbaritem>
+                <nut-sidenavbaritem ikey="11" title="细粒度人像分割1"></nut-sidenavbaritem>
+            </nut-subsidenavbar>
+            <nut-subsidenavbar title="人体识别2" ikey="12">
+                <nut-sidenavbaritem ikey="13" title="人体检测2"></nut-sidenavbaritem>
+                <nut-sidenavbaritem ikey="14" title="细粒度人像分割2"></nut-sidenavbaritem>
+            </nut-subsidenavbar>
         </nut-subsidenavbar>
     </nut-sidenavbar>
 </nut-popup>

+ 8 - 6
src/packages/sidenavbar/sidenavbar.vue

@@ -17,17 +17,19 @@ export default {
     }
   },
   mounted() {
+    this.handleSlots()
     this.observer = new MutationObserver(
       function(mutations) {
+        this.count = 1
         this.handleSlots();
       }.bind(this)
     );
 
     this.observer.observe(this.$refs.list, {
-      attributes: true,
+      attributes: false,
       childList: true,
-      characterData: true,
-      subtree: true
+      characterData: false,
+      subtree: false
     });
   },
   data() {
@@ -52,12 +54,12 @@ export default {
       for (let i = 0; i < nodeList.length; i++) {
         let item = nodeList[i];
         item.children[0].style.paddingLeft = this.offset * level + 'px';
-        if (item.className !== 'nut-sidenavbaritem') {
+        if (!item.className.includes('nut-sidenavbaritem')) {
           this.setPaddingLeft(Array.from(item.children[1].children), ++this.count);
         }
       }
-      this.count = 1;
+      this.count--
     }
   }
 };
-</script>
+</script>

+ 17 - 14
src/packages/swiper/swiper.vue

@@ -1,26 +1,18 @@
 <template>
-  <div class="nut-swiper" :class="[direction, { dragging: dragging }]" @touchstart="_onTouchStart($event)" @mousedown="_onTouchStart($event)">
-    <div
-      class="nut-swiper-wrap"
-      :style="{
+  <div class="nut-swiper" :class="[direction, { dragging: dragging }]" @touchstart="_onTouchStart($event)"
+    @mousedown="_onTouchStart($event)">
+    <div class="nut-swiper-wrap" :style="{
         transform: 'translate3d(' + translateX + 'px,' + translateY + 'px,0)',
         'transition-duration': transitionDuration + 'ms',
         '-webkit-transform': 'translate3d(' + translateX + 'px,' + translateY + 'px,0)',
         '-webkit-transition-duration': transitionDuration + 'ms',
         'transition-timing-function': 'ease'
-      }"
-      @transitionend="_onTransitionEnd"
-    >
+      }" @transitionend="_onTransitionEnd">
       <slot></slot>
     </div>
     <div class="nut-swiper-pagination" v-show="paginationVisible">
-      <span
-        class="swiper-pagination-bullet"
-        :class="{ active: index + 1 === currentPage }"
-        v-for="(slide, index) in slideEls"
-        :key="index"
-        @click="paginationClickable && setPage(index + 1, true)"
-      >
+      <span class="swiper-pagination-bullet" :class="{ active: index + 1 === currentPage }"
+        v-for="(slide, index) in slideEls" :key="index" @click="paginationClickable && setPage(index + 1, true)">
       </span>
     </div>
   </div>
@@ -400,6 +392,17 @@ export default {
   destroyed() {
     this.timer = null;
     this.domTimer = null;
+  },
+  activated() {
+    if (this.keepAlive) {
+      this.keepAlive = false;
+      this.updateEvent();
+    }
+  },
+  deactivated() {
+    this.keepAlive = true;
+    this.timer = null;
+    this.domTimer = null;
   }
 };
 </script>

+ 36 - 0
src/utils/event.js

@@ -0,0 +1,36 @@
+export let passiveSupported = false;
+
+ 
+try {
+    var options = Object.defineProperty({}, "passive", {
+      get: function() {
+        passiveSupported = true;
+      }
+    });
+  
+    window.addEventListener("test", null, options);
+} catch(err) {}
+  
+ 
+export function on(
+  target,
+  event,
+  handler,
+  passive = false
+) {
+ 
+    target.addEventListener(
+      event,
+      handler,
+      passiveSupported ? { capture: false, passive } : false
+    );
+ 
+}
+
+export function off(target, event, handler) {
+    target.removeEventListener(event, handler); 
+}
+ 
+
+ 
+