Browse Source

Merge branch 'next' of https://github.com/jdf2e/nutui into next

richard1015 4 years ago
parent
commit
817251b691

+ 1 - 0
src/config.json

@@ -301,6 +301,7 @@
         },
         {
           "name": "Popup",
+          "taro": true,
           "sort": 8,
           "cName": "弹出层",
           "type": "component",

+ 259 - 0
src/packages/__VUE/popup/index.taro.vue

@@ -0,0 +1,259 @@
+<template>
+  <view>
+    <nut-overlay
+      v-if="overlay"
+      :visible="visible"
+      :close-on-click-overlay="closeOnClickOverlay"
+      :class="overlayClass"
+      :style="overlayStyle"
+      :z-index="zIndex"
+      :lock-scroll="lockScroll"
+      :duration="duration"
+      @click="onClickOverlay"
+    />
+    <Transition
+      :name="transitionName"
+      @after-enter="onOpened"
+      @after-leave="onClosed"
+    >
+      <view
+        v-show="visible"
+        :class="classes"
+        :style="popStyle"
+        @click="onClick"
+      >
+        <slot v-if="showSlot"></slot>
+        <nut-icon
+          v-if="closeable"
+          @click="onClickCloseIcon"
+          :name="closeIcon"
+          size="12px"
+          class="nutui-popup__close-icon"
+          :class="'nutui-popup__close-icon--' + closeIconPosition"
+        >
+        </nut-icon>
+      </view>
+    </Transition>
+  </view>
+</template>
+<script lang="ts">
+import {
+  onMounted,
+  onBeforeMount,
+  onBeforeUnmount,
+  onActivated,
+  onDeactivated,
+  watch,
+  computed,
+  reactive,
+  PropType,
+  CSSProperties,
+  toRefs,
+  getCurrentInstance
+} from 'vue';
+import { useLockScroll } from '@/packages/__VUE/popup/use-lock-scroll';
+import { overlayProps } from '@/packages/__VUE/overlay/index.taro.vue';
+import overlay from '@/packages/__VUE/overlay/index.taro.vue';
+import { createComponent } from '@/packages/utils/create';
+const { componentName, create } = createComponent('popup');
+let _zIndex = 2000;
+export const popupProps = {
+  ...overlayProps,
+  position: {
+    type: String,
+    default: 'center'
+  },
+  transition: String,
+  style: {
+    type: Object as PropType<CSSProperties>
+  },
+  popClass: {
+    type: String,
+    default: ''
+  },
+  closeable: {
+    type: Boolean,
+    default: false
+  },
+  closeIconPosition: {
+    type: String,
+    default: 'top-right'
+  },
+  closeIcon: {
+    type: String,
+    default: 'close'
+  },
+  destroyOnClose: {
+    type: Boolean,
+    default: true
+  },
+  teleport: {
+    type: [String, Element],
+    default: 'body'
+  },
+  overlay: {
+    type: Boolean,
+    default: true
+  },
+  round: {
+    type: Boolean,
+    default: false
+  }
+};
+export default create({
+  children: [overlay],
+  components: {
+    'nut-overlay': overlay
+  },
+  props: {
+    ...popupProps
+  },
+  emits: [
+    'click',
+    'click-close-icon',
+    'open',
+    'close',
+    'opend',
+    'closed',
+    'update:visible',
+    'click-overlay'
+  ],
+  setup(props, { emit }) {
+    const { proxy } = getCurrentInstance() as any;
+    const state = reactive({
+      zIndex: props.zIndex ? (props.zIndex as number) : _zIndex,
+      showSlot: true,
+      transitionName: `popup-fade-${props.position}`,
+      overLayCount: 1,
+      keepAlive: false
+    });
+    const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll);
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      return {
+        [prefixCls]: true,
+        ['round']: props.round,
+        [`popup-${props.position}`]: true,
+        [props.popClass]: true
+      };
+    });
+    const popStyle = computed(() => {
+      return {
+        zIndex: state.zIndex,
+        animationDuration: props.duration ? `${props.duration}s` : 'initial',
+        ...props.style
+      };
+    });
+    const open = () => {
+      if (!props.visible) {
+        if (props.zIndex !== undefined) {
+          _zIndex = Number(props.zIndex);
+        }
+        emit('update:visible', true);
+        lockScroll();
+        state.zIndex = ++_zIndex;
+      }
+      if (props.destroyOnClose) {
+        state.showSlot = true;
+      }
+      emit('open');
+    };
+    const close = () => {
+      if (props.visible) {
+        unlockScroll();
+        emit('update:visible', false);
+        if (props.destroyOnClose) {
+          setTimeout(() => {
+            state.showSlot = false;
+            emit('close');
+          }, +props.duration * 1000);
+        }
+      }
+    };
+    const onClick = (e: Event) => {
+      emit('click', e);
+    };
+    const onClickCloseIcon = (e: Event) => {
+      emit('click-close-icon', e);
+      close();
+    };
+    const onClickOverlay = (e: Event) => {
+      if (props.closeOnClickOverlay) {
+        emit('click-overlay', e);
+        close();
+      }
+    };
+    const onOpened = (e: Event) => {
+      emit('opend', e);
+    };
+    const onClosed = (e: Event) => {
+      emit('closed', e);
+    };
+    onMounted(() => {
+      // document.getElementById('app').appendChild(proxy.$el);
+      const query = wx.createSelectorQuery();
+      // console.log(query.in(proxy));
+      query.selectViewport().scrollOffset();
+      query.exec(res => {
+        // console.log(res[0].scrollTop)
+      });
+      props.transition
+        ? (state.transitionName = props.transition)
+        : (state.transitionName = `popup-slide-${props.position}`);
+      props.visible && open();
+    });
+    onBeforeUnmount(() => {
+      props.visible && close();
+    });
+    onBeforeMount(() => {
+      if (props.visible) {
+        unlockScroll();
+      }
+    });
+    onActivated(() => {
+      if (state.keepAlive) {
+        emit('update:visible', true);
+        state.keepAlive = false;
+      }
+    });
+    onDeactivated(() => {
+      if (props.visible) {
+        close();
+        state.keepAlive = true;
+      }
+    });
+    watch(
+      () => props.visible,
+      value => {
+        if (value) {
+          open();
+        } else {
+          close();
+        }
+      }
+    );
+    watch(
+      () => props.position,
+      value => {
+        value === 'center'
+          ? (state.transitionName = 'popup-fade')
+          : (state.transitionName = `popup-slide-${value}`);
+      }
+    );
+    return {
+      ...toRefs(state),
+      popStyle,
+      classes,
+      onClick,
+      onClickCloseIcon,
+      onClickOverlay,
+      onOpened,
+      onClosed
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

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

@@ -1,5 +1,6 @@
 export default {
   pages: [
+    'pages/popup/index',
     'pages/icon/index',
     'pages/inputnumber/index',
     'pages/tabbar/index',

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

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

+ 140 - 0
src/sites/mobile-taro/vue/src/pages/popup/index.vue

@@ -0,0 +1,140 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-cell
+      title="展示弹出层"
+      is-link
+      @click="state.showBasic = true"
+    ></nut-cell>
+    <nut-popup
+      pop-class="popclass"
+      :style="{ padding: '30px 50px' }"
+      v-model:visible="state.showBasic"
+      :z-index="100"
+      >正文</nut-popup
+    >
+    <h2>弹出位置</h2>
+    <nut-cell title="顶部弹出" is-link @click="state.showTop = true"></nut-cell>
+    <nut-popup
+      position="top"
+      :style="{ height: '20%' }"
+      v-model:visible="state.showTop"
+    ></nut-popup>
+    <nut-cell
+      title="底部弹出"
+      is-link
+      @click="state.showBottom = true"
+    ></nut-cell>
+    <nut-popup
+      position="bottom"
+      :style="{ height: '20%' }"
+      v-model:visible="state.showBottom"
+    ></nut-popup>
+    <nut-cell
+      title="左侧弹出"
+      is-link
+      @click="state.showLeft = true"
+    ></nut-cell>
+    <nut-popup
+      position="left"
+      :style="{ width: '20%', height: '100%' }"
+      v-model:visible="state.showLeft"
+    ></nut-popup>
+    <nut-cell
+      title="右侧弹出"
+      is-link
+      @click="state.showRight = true"
+    ></nut-cell>
+    <nut-popup
+      position="right"
+      :style="{ width: '20%', height: '100%' }"
+      v-model:visible="state.showRight"
+    ></nut-popup>
+    <h2>关闭图标</h2>
+    <nut-cell
+      title="关闭图标"
+      is-link
+      @click="state.showIcon = true"
+    ></nut-cell>
+    <nut-popup
+      position="bottom"
+      closeable
+      :style="{ height: '20%' }"
+      v-model:visible="state.showIcon"
+    ></nut-popup>
+    <nut-cell
+      title="图标位置"
+      is-link
+      @click="state.showIconPosition = true"
+    ></nut-cell>
+    <nut-popup
+      position="bottom"
+      closeable
+      close-icon-position="top-left"
+      :style="{ height: '20%' }"
+      v-model:visible="state.showIconPosition"
+    ></nut-popup>
+    <nut-cell
+      title="自定义图标"
+      is-link
+      @click="state.showCloseIcon = true"
+    ></nut-cell>
+    <nut-popup
+      position="bottom"
+      closeable
+      close-icon-position="top-left"
+      close-icon="heart"
+      :style="{ height: '20%' }"
+      v-model:visible="state.showCloseIcon"
+    ></nut-popup>
+    <h2>圆角弹框</h2>
+    <nut-cell
+      title="圆角弹框"
+      is-link
+      @click="state.showRound = true"
+    ></nut-cell>
+    <nut-popup
+      position="bottom"
+      closeable
+      round
+      :style="{ height: '30%' }"
+      v-model:visible="state.showRound"
+    ></nut-popup>
+    <h2>指定挂载节点</h2>
+    <nut-cell
+      title="指定挂载节点"
+      is-link
+      @click="state.showTeleport = true"
+    ></nut-cell>
+    <nut-popup
+      :style="{ padding: '30px 50px' }"
+      teleport="#app"
+      v-model:visible="state.showTeleport"
+      >app</nut-popup
+    >
+  </div>
+</template>
+
+<script lang="ts">
+import { reactive } from 'vue';
+export default {
+  props: {},
+  setup() {
+    const state = reactive({
+      showBasic: false,
+      showTop: false,
+      showBottom: false,
+      showLeft: false,
+      showRight: false,
+      showIcon: false,
+      showIconPosition: false,
+      showCloseIcon: false,
+      showRound: false,
+      showCombination: false
+    });
+    return { state };
+  }
+};
+</script>
+
+<style lang="scss" scoped></style>