ソースを参照

feat: tour 组件新增功能 (#1977)

* fix: 地址icon修改

* fix: 组件icon问题修改

* fix: 地址组件修改

* fix: 地址删除props

* feat: 组件dts修改

* fix: 组件Tour和Audio添加依赖

* feat: tour新增功能

Co-authored-by: yangxiaolu3 <yangxiaolu3@jd.com>
yangxiaolu1993 3 年 前
コミット
877588e961

+ 41 - 29
src/packages/__VUE/popover/index.taro.vue

@@ -7,7 +7,7 @@
     :id="'popoverRef' + refRandomId"
     :id="'popoverRef' + refRandomId"
     ><slot name="reference"></slot
     ><slot name="reference"></slot
   ></view>
   ></view>
-  <view :class="['nut-popover', `nut-popover--${theme}`, `${customClass}`]" :style="getRootPosition">
+  <view :class="['nut-popover', `nut-popover--${theme}`, `${customClass}`]" :style="popoverstyles" ref="popoverbox">
     <nut-popup
     <nut-popup
       :popClass="`nut-popover-content nut-popover-content--${location}`"
       :popClass="`nut-popover-content nut-popover-content--${location}`"
       :style="customStyle"
       :style="customStyle"
@@ -46,6 +46,7 @@
   <!-- TODO -->
   <!-- TODO -->
   <div :class="`nut-popover-content nut-popover-content-copy`">
   <div :class="`nut-popover-content nut-popover-content-copy`">
     <view ref="popoverContentRefCopy" :id="'popoverContentRefCopy' + refRandomId" class="nut-popover-content-group">
     <view ref="popoverContentRefCopy" :id="'popoverContentRefCopy' + refRandomId" class="nut-popover-content-group">
+      <view :class="popoverArrow" v-if="showArrow" :style="popoverArrowStyle"> </view>
       <slot name="content"></slot>
       <slot name="content"></slot>
       <view
       <view
         v-for="(item, index) in list"
         v-for="(item, index) in list"
@@ -67,8 +68,7 @@
 import { onMounted, computed, watch, ref, PropType, CSSProperties } from 'vue';
 import { onMounted, computed, watch, ref, PropType, CSSProperties } from 'vue';
 import { createComponent, renderIcon } from '@/packages/utils/create';
 import { createComponent, renderIcon } from '@/packages/utils/create';
 const { componentName, create } = createComponent('popover');
 const { componentName, create } = createComponent('popover');
-import { useTaroRect } from '@/packages/utils/useTaroRect';
-import { rect } from '@/packages/utils/useRect';
+import { useTaroRect, rectTaro } from '@/packages/utils/useTaroRect';
 import { isArray } from '@/packages/utils/util';
 import { isArray } from '@/packages/utils/util';
 import { PopoverList, PopoverTheme, PopoverLocation } from './type';
 import { PopoverList, PopoverTheme, PopoverLocation } from './type';
 import Taro from '@tarojs/taro';
 import Taro from '@tarojs/taro';
@@ -89,7 +89,7 @@ export default create({
     customClass: { type: String, default: '' },
     customClass: { type: String, default: '' },
     showArrow: { type: Boolean, default: true },
     showArrow: { type: Boolean, default: true },
     iconPrefix: { type: String, default: 'nut-icon' },
     iconPrefix: { type: String, default: 'nut-icon' },
-    duration: { type: [Number, String], default: 0.3 },
+    duration: { type: [Number, String], default: 0.2 },
     overlay: { type: Boolean, default: false },
     overlay: { type: Boolean, default: false },
     overlayClass: { type: String, default: '' },
     overlayClass: { type: String, default: '' },
     overlayStyle: { type: Object as PropType<CSSProperties> },
     overlayStyle: { type: Object as PropType<CSSProperties> },
@@ -104,14 +104,16 @@ export default create({
     const popoverRef = ref();
     const popoverRef = ref();
     const popoverContentRef = ref();
     const popoverContentRef = ref();
     const popoverContentRefCopy = ref();
     const popoverContentRefCopy = ref();
+    const popoverbox = ref();
     const showPopup = ref(props.visible);
     const showPopup = ref(props.visible);
+    const popoverstyles = ref<CSSProperties>({});
 
 
-    let rootRect = ref<rect>();
+    let rootRect = ref<rectTaro>();
 
 
-    let conentRootRect = ref<{
+    let conentRootRect: {
       height: number;
       height: number;
       width: number;
       width: number;
-    }>();
+    };
 
 
     const popoverArrow = computed(() => {
     const popoverArrow = computed(() => {
       const prefixCls = 'nut-popover-arrow';
       const prefixCls = 'nut-popover-arrow';
@@ -164,14 +166,11 @@ export default create({
       return str;
       return str;
     };
     };
 
 
-    const getRootPosition = computed(() => {
-      let styles: CSSProperties = {};
-
-      if (!rootRect.value || !conentRootRect.value) return {};
-
-      const conentWidth = conentRootRect.value.width;
-      const conentHeight = conentRootRect.value.height;
+    const getRootPosition = () => {
+      if (!rootRect.value || !conentRootRect) return {};
 
 
+      const conentWidth = conentRootRect.width;
+      const conentHeight = conentRootRect.height;
       const { width, height, left, top } = rootRect.value;
       const { width, height, left, top } = rootRect.value;
 
 
       const { location, offset } = props;
       const { location, offset } = props;
@@ -183,39 +182,37 @@ export default create({
         cross += +offset[1];
         cross += +offset[1];
         parallel += +offset[0];
         parallel += +offset[0];
       }
       }
+
       if (width) {
       if (width) {
         if (['bottom', 'top'].includes(direction)) {
         if (['bottom', 'top'].includes(direction)) {
           const h = direction == 'bottom' ? height + cross : -(conentHeight + cross);
           const h = direction == 'bottom' ? height + cross : -(conentHeight + cross);
 
 
-          styles.top = `${top + h}px`;
-
+          popoverstyles.value.top = `${top + h}px`;
           if (!skew) {
           if (!skew) {
-            styles.left = `${-(conentWidth - width) / 2 + left + parallel}px`;
+            popoverstyles.value.left = `${-(conentWidth - width) / 2 + left + parallel}px`;
           }
           }
           if (skew == 'start') {
           if (skew == 'start') {
-            styles.left = `${left + parallel}px`;
+            popoverstyles.value.left = `${left + parallel}px`;
           }
           }
           if (skew == 'end') {
           if (skew == 'end') {
-            styles.left = `${rootRect.value.right + parallel}px`;
+            popoverstyles.value.left = `${rootRect.value.right + parallel}px`;
           }
           }
         }
         }
         if (['left', 'right'].includes(direction)) {
         if (['left', 'right'].includes(direction)) {
           const contentW = direction == 'left' ? -(conentWidth + cross) : width + cross;
           const contentW = direction == 'left' ? -(conentWidth + cross) : width + cross;
-          styles.left = `${left + contentW}px`;
+          popoverstyles.value.left = `${left + contentW}px`;
           if (!skew) {
           if (!skew) {
-            styles.top = `${top - conentHeight / 2 + height / 2 - 4 + parallel}px`;
+            popoverstyles.value.top = `${top - conentHeight / 2 + height / 2 - 4 + parallel}px`;
           }
           }
           if (skew == 'start') {
           if (skew == 'start') {
-            styles.top = `${top + parallel}px`;
+            popoverstyles.value.top = `${top + parallel}px`;
           }
           }
           if (skew == 'end') {
           if (skew == 'end') {
-            styles.top = `${top + height + parallel}px`;
+            popoverstyles.value.top = `${top + height + parallel}px`;
           }
           }
         }
         }
       }
       }
-
-      return styles;
-    });
+    };
 
 
     const customStyle = computed(() => {
     const customStyle = computed(() => {
       const styles: CSSProperties = {};
       const styles: CSSProperties = {};
@@ -234,15 +231,21 @@ export default create({
         rect = await useTaroRect(popoverRef, Taro);
         rect = await useTaroRect(popoverRef, Taro);
       }
       }
       rootRect.value = rect;
       rootRect.value = rect;
+
+      getRootPosition();
     };
     };
 
 
     const getPopoverContentW = async (type: number = 1) => {
     const getPopoverContentW = async (type: number = 1) => {
       const el = type == 1 ? popoverContentRef : popoverContentRefCopy;
       const el = type == 1 ? popoverContentRef : popoverContentRefCopy;
+
       let rectContent = await useTaroRect(el, Taro);
       let rectContent = await useTaroRect(el, Taro);
-      conentRootRect.value = {
+
+      conentRootRect = {
         height: rectContent.height,
         height: rectContent.height,
         width: rectContent.width
         width: rectContent.width
       };
       };
+
+      getRootPosition();
     };
     };
     watch(
     watch(
       () => props.visible,
       () => props.visible,
@@ -259,6 +262,13 @@ export default create({
         }
         }
       }
       }
     );
     );
+
+    watch(
+      () => props.location,
+      (value) => {
+        getRootPosition();
+      }
+    );
     const update = (val: boolean) => {
     const update = (val: boolean) => {
       emit('update', val);
       emit('update', val);
       emit('update:visible', val);
       emit('update:visible', val);
@@ -285,7 +295,7 @@ export default create({
       setTimeout(() => {
       setTimeout(() => {
         getContentWidth();
         getContentWidth();
         getPopoverContentW(0);
         getPopoverContentW(0);
-      }, 200);
+      }, 600);
     });
     });
 
 
     const refRandomId = Math.random().toString(36).slice(-8);
     const refRandomId = Math.random().toString(36).slice(-8);
@@ -304,7 +314,9 @@ export default create({
       popoverArrowStyle,
       popoverArrowStyle,
       customStyle,
       customStyle,
       getRootPosition,
       getRootPosition,
-      renderIcon
+      renderIcon,
+      popoverbox,
+      popoverstyles
     };
     };
   }
   }
 });
 });

+ 5 - 3
src/packages/__VUE/tour/doc.en-US.md

@@ -9,12 +9,10 @@ A bubble component used to guide the user through the product's capabilities. Th
 ```javascript
 ```javascript
 
 
 import { createApp } from 'vue';
 import { createApp } from 'vue';
-import { Tour, Popover, Popup } from '@nutui/nutui';
+import { Tour } from '@nutui/nutui';
 
 
 const app = createApp();
 const app = createApp();
 
 
-app.use(Popup);
-app.use(Popover);
 app.use(Tour);
 app.use(Tour);
 
 
 ```
 ```
@@ -285,6 +283,8 @@ export default {
 | mask-width       | Width of hollow mask  | Number、String  | '' |
 | mask-width       | Width of hollow mask  | Number、String  | '' |
 | mask-height       | Hollow mask height  | Number、String  | '' |
 | mask-height       | Hollow mask height  | Number、String  | '' |
 | close-on-click-overlay      | Whether to close when clicking overlay,[closeOnClickOverlay](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
 | close-on-click-overlay      | Whether to close when clicking overlay,[closeOnClickOverlay](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
+| show-prev-step       | Whether to show prev button  | boolean  | true |
+| show-title-bar       | Whether to show title bar  |  boolean  | false |
 
 
 ### StepOptions  
 ### StepOptions  
 
 
@@ -302,6 +302,8 @@ export default {
 | Name   | Description           |
 | Name   | Description           |
 |---------|--------------|
 |---------|--------------|
 | default | Custom popover content |
 | default | Custom popover content |
+| prevStep | Custom prev strep content|
+| nextStep |  Custom prev strep content |
 
 
 ### Events
 ### Events
 
 

+ 6 - 4
src/packages/__VUE/tour/doc.md

@@ -9,12 +9,10 @@
 ```javascript
 ```javascript
 
 
 import { createApp } from 'vue';
 import { createApp } from 'vue';
-import { Tour, Popover, Popup } from '@nutui/nutui';
+import { Tour } from '@nutui/nutui';
 
 
 const app = createApp();
 const app = createApp();
 
 
-app.use(Popup);
-app.use(Popover);
 app.use(Tour);
 app.use(Tour);
 
 
 ```
 ```
@@ -286,6 +284,8 @@ export default {
 | mask-width       | 镂空遮罩层宽度  | Number、String  | '' |
 | mask-width       | 镂空遮罩层宽度  | Number、String  | '' |
 | mask-height       | 镂空遮罩层高度  | Number、String  | '' |
 | mask-height       | 镂空遮罩层高度  | Number、String  | '' |
 | close-on-click-overlay      | 是否在点击镂空遮罩层后关闭,同 Popopver 的[closeOnClickOverlay 属性](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
 | close-on-click-overlay      | 是否在点击镂空遮罩层后关闭,同 Popopver 的[closeOnClickOverlay 属性](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
+| show-prev-step       | 是否展示上一步按钮  | boolean  | true |
+| show-title-bar       | 是否展示标题栏  |  boolean  | false |
 
 
 ### StepOptions  
 ### StepOptions  
 
 
@@ -302,7 +302,9 @@ export default {
 
 
 | 名称    | 说明         |
 | 名称    | 说明         |
 |---------|--------------|
 |---------|--------------|
-| default | 自定义气泡层内容 |
+| default | 自定义气泡层内容|
+|prevStep | 自定义上一步内容|
+|nextStep | 自定义下一步内容 |
 
 
 ### Events
 ### Events
 
 

+ 5 - 3
src/packages/__VUE/tour/doc.taro.md

@@ -9,12 +9,10 @@
 ```javascript
 ```javascript
 
 
 import { createApp } from 'vue';
 import { createApp } from 'vue';
-import { Tour, Popover, Popup } from '@nutui/nutui-taro';
+import { Tour } from '@nutui/nutui-taro';
 
 
 const app = createApp();
 const app = createApp();
 
 
-app.use(Popup);
-app.use(Popover);
 app.use(Tour);
 app.use(Tour);
 
 
 ```
 ```
@@ -286,6 +284,8 @@ export default {
 | mask-width       | 镂空遮罩层宽度  | Number、String  | '' |
 | mask-width       | 镂空遮罩层宽度  | Number、String  | '' |
 | mask-height       | 镂空遮罩层高度  | Number、String  | '' |
 | mask-height       | 镂空遮罩层高度  | Number、String  | '' |
 | close-on-click-overlay      | 是否在点击镂空遮罩层后关闭,同 Popopver 的[closeOnClickOverlay 属性](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
 | close-on-click-overlay      | 是否在点击镂空遮罩层后关闭,同 Popopver 的[closeOnClickOverlay 属性](https://nutui.jd.com/#/zh-CN/component/popover)  | Boolean  | true |
+| show-prev-step       | 是否展示上一步按钮  | boolean  | true |
+| show-title-bar       | 是否展示标题栏  |  boolean  | false |
 
 
 ### StepOptions  
 ### StepOptions  
 
 
@@ -303,6 +303,8 @@ export default {
 | 名称    | 说明         |
 | 名称    | 说明         |
 |---------|--------------|
 |---------|--------------|
 | default | 自定义气泡层内容 |
 | default | 自定义气泡层内容 |
+|prevStep | 自定义上一步内容|
+|nextStep | 自定义下一步内容 |
 
 
 ### Events
 ### Events
 
 

+ 4 - 0
src/packages/__VUE/tour/index.scss

@@ -9,6 +9,10 @@
     &-none {
     &-none {
       box-shadow: none;
       box-shadow: none;
     }
     }
+
+    &-hidden {
+      opacity: 0;
+    }
   }
   }
 
 
   &-content {
   &-content {

+ 105 - 75
src/packages/__VUE/tour/index.taro.vue

@@ -1,73 +1,82 @@
 <template>
 <template>
   <view :class="classes">
   <view :class="classes">
-    <view class="nut-tour-masked" v-show="showTour" @click="handleClickMask"></view>
+    <view class="nut-tour-masked" v-if="showTour" @click="handleClickMask"></view>
 
 
     <view v-for="(step, i) in steps" :key="i" style="height: 0">
     <view v-for="(step, i) in steps" :key="i" style="height: 0">
-      <template v-if="i == active">
-        <view
-          class="nut-tour-mask"
-          :class="[mask ? '' : 'nut-tour-mask-none']"
-          :style="maskStyle"
-          v-if="showTour"
-          id="nut-tour-popid"
-        ></view>
-        <nut-popover
-          v-model:visible="showPopup"
-          :location="step.location || location"
-          targetId="nut-tour-popid"
-          :bgColor="bgColor"
-          :theme="theme"
-          :close-on-click-outside="false"
-          :offset="step.popoverOffset || [0, 12]"
-          :arrowOffset="step.arrowOffset || 0"
-        >
-          <template v-slot:content>
-            <slot>
-              <view class="nut-tour-content" v-if="type == 'step'">
-                <view class="nut-tour-content-top">
-                  <view @click="close">
-                    <Close class="nut-tour-content-top-close" />
-                  </view>
+      <view
+        class="nut-tour-mask"
+        :class="[mask ? (showPopup[i] ? '' : 'nut-tour-mask-hidden') : 'nut-tour-mask-none']"
+        :style="maskStyles[i]"
+        :id="`nut-tour-popid${i}${refRandomId}`"
+      ></view>
+      <nut-popover
+        v-model:visible="showPopup[i]"
+        :location="step.location || location"
+        :targetId="`nut-tour-popid${i}${refRandomId}`"
+        :bgColor="bgColor"
+        :theme="theme"
+        :close-on-click-outside="false"
+        :offset="step.popoverOffset || [0, 12]"
+        :arrowOffset="step.arrowOffset || 0"
+        :duration="0.2"
+      >
+        <template v-slot:content>
+          <slot>
+            <view class="nut-tour-content" v-if="type == 'step'">
+              <view class="nut-tour-content-top" v-if="showTitleBar">
+                <view @click="close">
+                  <Close class="nut-tour-content-top-close" />
                 </view>
                 </view>
-                <view class="nut-tour-content-inner">
-                  {{ step.content }}
-                </view>
-                <view class="nut-tour-content-bottom">
-                  <view class="nut-tour-content-bottom-init">{{ active + 1 }}/{{ steps.length }}</view>
-                  <view class="nut-tour-content-bottom-operate">
-                    <view class="nut-tour-content-bottom-operate-btn" @click="changeStep('prev')" v-if="active != 0">{{
-                      prevStepTxt
-                    }}</view>
+              </view>
+              <view class="nut-tour-content-inner">
+                {{ step.content }}
+              </view>
+              <view class="nut-tour-content-bottom">
+                <view class="nut-tour-content-bottom-init">{{ active + 1 }}/{{ steps.length }}</view>
+                <view class="nut-tour-content-bottom-operate">
+                  <slot name="prevStep">
+                    <view
+                      class="nut-tour-content-bottom-operate-btn"
+                      @click="changeStep('prev')"
+                      v-if="active != 0 && showPrevStep"
+                      >{{ prevStepTxt }}</view
+                    >
+                  </slot>
+                  <view
+                    class="nut-tour-content-bottom-operate-btn active"
+                    @click="close"
+                    v-if="steps.length - 1 == active"
+                    >{{ completeTxt }}</view
+                  >
+
+                  <slot name="nextStep">
                     <view
                     <view
                       class="nut-tour-content-bottom-operate-btn active"
                       class="nut-tour-content-bottom-operate-btn active"
-                      @click="close"
-                      v-if="steps.length - 1 == active"
-                      >{{ completeTxt }}</view
+                      @click="changeStep('next')"
+                      v-if="steps.length - 1 != active"
+                      >{{ nextStepTxt }}</view
                     >
                     >
-                    <view class="nut-tour-content-bottom-operate-btn active" @click="changeStep('next')" v-else>{{
-                      nextStepTxt
-                    }}</view>
-                  </view>
+                  </slot>
                 </view>
                 </view>
               </view>
               </view>
+            </view>
 
 
-              <view class="nut-tour-content nut-tour-content-tile" v-if="type == 'tile'">
-                <view class="nut-tour-content-inner">
-                  {{ step.content }}
-                </view>
+            <view class="nut-tour-content nut-tour-content-tile" v-if="type == 'tile'">
+              <view class="nut-tour-content-inner">
+                {{ step.content }}
               </view>
               </view>
-            </slot>
-          </template>
-        </nut-popover>
-      </template>
+            </view>
+          </slot>
+        </template>
+      </nut-popover>
     </view>
     </view>
   </view>
   </view>
 </template>
 </template>
 <script lang="ts">
 <script lang="ts">
-import { computed, watch, ref, reactive, toRefs, PropType, nextTick, onMounted, Component } from 'vue';
+import { computed, watch, ref, reactive, toRefs, PropType, nextTick, onMounted, Component, CSSProperties } from 'vue';
 import { PopoverLocation } from '../popover/type';
 import { PopoverLocation } from '../popover/type';
 import { createComponent } from '@/packages/utils/create';
 import { createComponent } from '@/packages/utils/create';
-import { useTaroRect } from '@/packages/utils/useTaroRect';
+import { useTaroRect, rectTaro } from '@/packages/utils/useTaroRect';
 import { Close } from '@nutui/icons-vue-taro';
 import { Close } from '@nutui/icons-vue-taro';
 import Taro from '@tarojs/taro';
 import Taro from '@tarojs/taro';
 import Popover from '../popover/index.taro.vue';
 import Popover from '../popover/index.taro.vue';
@@ -142,28 +151,39 @@ export default create({
     closeOnClickOverlay: {
     closeOnClickOverlay: {
       type: Boolean,
       type: Boolean,
       default: true
       default: true
+    },
+    showPrevStep: {
+      type: Boolean,
+      default: true
+    },
+    showTitleBar: {
+      type: Boolean,
+      default: true
     }
     }
   },
   },
   emits: ['update:visible', 'change', 'close'],
   emits: ['update:visible', 'change', 'close'],
   setup(props, { emit }) {
   setup(props, { emit }) {
     const state = reactive({
     const state = reactive({
       showTour: props.visible,
       showTour: props.visible,
-      showPopup: false,
       active: 0
       active: 0
     });
     });
 
 
-    const maskRect = ref<{
-      [props: string]: number;
-    }>({});
+    const showPopup = ref([false]);
+
+    let maskRect: rectTaro[] = [];
+
+    let maskStyles = ref<CSSProperties[]>([]);
 
 
     const classes = computed(() => {
     const classes = computed(() => {
       const prefixCls = 'nut-tour';
       const prefixCls = 'nut-tour';
       return `${prefixCls}`;
       return `${prefixCls}`;
     });
     });
 
 
-    const maskStyle = computed(() => {
+    const maskStyle = (index: number) => {
       const { offset, maskWidth, maskHeight } = props;
       const { offset, maskWidth, maskHeight } = props;
-      const { width, height, left, top } = maskRect.value;
+
+      if (!maskRect[index]) return {};
+      const { width, height, left, top } = maskRect[index];
 
 
       const center = [left + width / 2, top + height / 2]; // 中心点 【横,纵】
       const center = [left + width / 2, top + height / 2]; // 中心点 【横,纵】
       const w: number = Number(maskWidth ? maskWidth : width);
       const w: number = Number(maskWidth ? maskWidth : width);
@@ -175,33 +195,39 @@ export default create({
         top: `${center[1] - h / 2 - +offset[0]}px`,
         top: `${center[1] - h / 2 - +offset[0]}px`,
         left: `${center[0] - w / 2 - +offset[1]}px`
         left: `${center[0] - w / 2 - +offset[1]}px`
       };
       };
-      return styles;
-    });
+      maskStyles.value[index] = styles;
+    };
 
 
     const changeStep = (type: string) => {
     const changeStep = (type: string) => {
+      const current = state.active;
+      let next = current;
+
       if (type == 'next') {
       if (type == 'next') {
-        state.active = state.active + 1;
+        next = current + 1;
       } else {
       } else {
-        state.active = state.active - 1;
+        next = current - 1;
       }
       }
+      showPopup.value[current] = false;
 
 
-      state.showPopup = false;
-      nextTick(() => {
-        state.showPopup = true;
-        getRootPosition();
-      });
+      setTimeout(() => {
+        showPopup.value[next] = true;
+        state.active = next;
+      }, 300);
 
 
       emit('change', state.active);
       emit('change', state.active);
     };
     };
 
 
-    const getRootPosition = async () => {
-      const rect = await useTaroRect(props.steps[state.active].target, Taro);
-      maskRect.value = rect;
+    const getRootPosition = () => {
+      props.steps.forEach(async (item, i) => {
+        const rect = await useTaroRect(item.target, Taro);
+        maskRect[i] = rect;
+        maskStyle(i);
+      });
     };
     };
 
 
     const close = () => {
     const close = () => {
       state.showTour = false;
       state.showTour = false;
-      state.showPopup = false;
+      showPopup.value[state.active] = false;
       emit('close', state.active);
       emit('close', state.active);
       emit('update:visible', false);
       emit('update:visible', false);
     };
     };
@@ -213,7 +239,7 @@ export default create({
     onMounted(() => {
     onMounted(() => {
       setTimeout(() => {
       setTimeout(() => {
         getRootPosition();
         getRootPosition();
-      }, 200);
+      }, 500);
     });
     });
 
 
     watch(
     watch(
@@ -223,19 +249,23 @@ export default create({
           state.active = 0;
           state.active = 0;
           getRootPosition();
           getRootPosition();
         }
         }
-
         state.showTour = val;
         state.showTour = val;
-        state.showPopup = val;
+        showPopup.value[state.active] = val;
       }
       }
     );
     );
 
 
+    const refRandomId = Math.random().toString(36).slice(-8);
+
     return {
     return {
       ...toRefs(state),
       ...toRefs(state),
       classes,
       classes,
       maskStyle,
       maskStyle,
       changeStep,
       changeStep,
+      showPopup,
       close,
       close,
-      handleClickMask
+      handleClickMask,
+      maskStyles,
+      refRandomId
     };
     };
   }
   }
 });
 });

+ 34 - 7
src/packages/__VUE/tour/index.vue

@@ -24,7 +24,7 @@
           <template #content>
           <template #content>
             <slot>
             <slot>
               <div class="nut-tour-content" v-if="type == 'step'">
               <div class="nut-tour-content" v-if="type == 'step'">
-                <div class="nut-tour-content-top">
+                <div class="nut-tour-content-top" v-if="showTitleBar">
                   <div @click="close">
                   <div @click="close">
                     <Close class="nut-tour-content-top-close" />
                     <Close class="nut-tour-content-top-close" />
                   </div>
                   </div>
@@ -35,18 +35,29 @@
                 <div class="nut-tour-content-bottom">
                 <div class="nut-tour-content-bottom">
                   <div class="nut-tour-content-bottom-init">{{ active + 1 }}/{{ steps.length }}</div>
                   <div class="nut-tour-content-bottom-init">{{ active + 1 }}/{{ steps.length }}</div>
                   <div class="nut-tour-content-bottom-operate">
                   <div class="nut-tour-content-bottom-operate">
-                    <div class="nut-tour-content-bottom-operate-btn" @click="changeStep('prev')" v-if="active != 0">{{
-                      prevStepTxt
-                    }}</div>
+                    <slot name="prevStep">
+                      <div
+                        class="nut-tour-content-bottom-operate-btn"
+                        @click="changeStep('prev')"
+                        v-if="active != 0 && showPrevStep"
+                        >{{ prevStepTxt }}</div
+                      >
+                    </slot>
+
                     <div
                     <div
                       class="nut-tour-content-bottom-operate-btn active"
                       class="nut-tour-content-bottom-operate-btn active"
                       @click="close"
                       @click="close"
                       v-if="steps.length - 1 == active"
                       v-if="steps.length - 1 == active"
                       >{{ completeTxt }}</div
                       >{{ completeTxt }}</div
                     >
                     >
-                    <div class="nut-tour-content-bottom-operate-btn active" @click="changeStep('next')" v-else>{{
-                      nextStepTxt
-                    }}</div>
+                    <slot name="nextStep">
+                      <div
+                        class="nut-tour-content-bottom-operate-btn active"
+                        @click="changeStep('next')"
+                        v-if="steps.length - 1 != active"
+                        >{{ nextStepTxt }}</div
+                      >
+                    </slot>
                   </div>
                   </div>
                 </div>
                 </div>
               </div>
               </div>
@@ -141,6 +152,14 @@ export default create({
     closeOnClickOverlay: {
     closeOnClickOverlay: {
       type: Boolean,
       type: Boolean,
       default: true
       default: true
+    },
+    showPrevStep: {
+      type: Boolean,
+      default: true
+    },
+    showTitleBar: {
+      type: Boolean,
+      default: true
     }
     }
   },
   },
   emits: ['update:visible', 'change', 'close'],
   emits: ['update:visible', 'change', 'close'],
@@ -163,6 +182,14 @@ export default create({
       return `${prefixCls}`;
       return `${prefixCls}`;
     });
     });
 
 
+    // const maskClasses = computed(() => {
+    //   const prefixCls = 'nut-tour';
+    //   return {
+    //     [`${prefixCls}-mask`]:true,
+    //     [`${prefixCls}-mask-none`]:
+    //   }
+    // });
+
     const maskStyle = computed(() => {
     const maskStyle = computed(() => {
       const { offset, maskWidth, maskHeight } = props;
       const { offset, maskWidth, maskHeight } = props;
       const { width, height, left, top } = maskRect.value;
       const { width, height, left, top } = maskRect.value;

+ 10 - 0
src/packages/utils/useTaroRect/index.ts

@@ -12,6 +12,16 @@ import { Ref, unref } from 'vue';
 function isWindow(val: unknown): val is Window {
 function isWindow(val: unknown): val is Window {
   return val === window;
   return val === window;
 }
 }
+
+export interface rectTaro {
+  top: number;
+  left: number;
+  right: number;
+  bottom: number;
+  width: number;
+  height: number;
+}
+
 export const useTaroRect = (elementRef: (Element | Window | any) | Ref<Element | Window | any>, Taro: any): any => {
 export const useTaroRect = (elementRef: (Element | Window | any) | Ref<Element | Window | any>, Taro: any): any => {
   let element = unref(elementRef);
   let element = unref(elementRef);
 
 

+ 13 - 12
src/sites/mobile-taro/vue/src/exhibition/pages/tour/index.vue

@@ -92,7 +92,7 @@
 
 
     <!-- <h2>步骤</h2> -->
     <!-- <h2>步骤</h2> -->
 
 
-    <!-- <nut-cell title="点击试试" @click="showTour = true"></nut-cell>
+    <nut-cell title="点击试试" @click="showTour = true"></nut-cell>
 
 
     <nut-tabbar>
     <nut-tabbar>
       <nut-tabbar-item
       <nut-tabbar-item
@@ -119,9 +119,9 @@
         img="https://img14.360buyimg.com/imagetools/jfs/t1/156023/30/29042/4257/62e7c34aE71f32967/690e2db242e2a97f.png"
         img="https://img14.360buyimg.com/imagetools/jfs/t1/156023/30/29042/4257/62e7c34aE71f32967/690e2db242e2a97f.png"
         activeImg="https://img13.360buyimg.com/imagetools/jfs/t1/144283/8/28420/4851/62e74784Eaa8549fe/80535de2961b812e.png"
         activeImg="https://img13.360buyimg.com/imagetools/jfs/t1/144283/8/28420/4851/62e74784Eaa8549fe/80535de2961b812e.png"
       ></nut-tabbar-item>
       ></nut-tabbar-item>
-    </nut-tabbar> -->
+    </nut-tabbar>
 
 
-    <!-- <nut-tour
+    <nut-tour
       class="nut-customword-tour"
       class="nut-customword-tour"
       v-model:visible="showTour"
       v-model:visible="showTour"
       :steps="steps"
       :steps="steps"
@@ -129,11 +129,12 @@
       :offset="[0, 0]"
       :offset="[0, 0]"
       maskWidth="50"
       maskWidth="50"
       maskHeight="50"
       maskHeight="50"
-    ></nut-tour> -->
+      :showTitleBar="false"
+    ></nut-tour>
   </div>
   </div>
 </template>
 </template>
 <script lang="ts">
 <script lang="ts">
-import { reactive, ref, toRefs } from 'vue';
+import { reactive, toRefs } from 'vue';
 
 
 export default {
 export default {
   setup() {
   setup() {
@@ -146,20 +147,20 @@ export default {
       offset: [-3, -8],
       offset: [-3, -8],
       steps: [
       steps: [
         {
         {
-          content: '这里换成关注和粉丝啦,听歌时长点击头像可见',
+          content: '70+ 高质量组件,覆盖移动端主流场景',
           target: 'target1'
           target: 'target1'
         },
         },
         {
         {
-          content: '这里换成关注和粉丝啦,听歌时长点击头像可见',
+          content: '支持一套代码同时开发多端小程序+H5',
           target: 'target2'
           target: 'target2'
         },
         },
         {
         {
-          content: '这里换成关注和粉丝啦,听歌时长点击头像可见',
+          content: '基于京东APP 10.0 视觉规范',
           target: 'target3',
           target: 'target3',
           location: 'top-end'
           location: 'top-end'
         },
         },
         {
         {
-          content: '这里换成关注和粉丝啦,听歌时长点击头像可见',
+          content: '支持定制主题,内置 700+ 个主题变量',
           target: 'target4',
           target: 'target4',
           location: 'top-end'
           location: 'top-end'
         }
         }
@@ -167,14 +168,14 @@ export default {
 
 
       steps1: [
       steps1: [
         {
         {
-          content: '邀请有礼,全新改版,奖励多多哦',
+          content: '70+ 高质量组件,覆盖移动端主流场景',
           target: 'target5'
           target: 'target5'
         }
         }
       ],
       ],
 
 
       steps2: [
       steps2: [
         {
         {
-          content: '这里换成关注和粉丝啦,听歌时长点击头像可见',
+          content: '支持一套代码同时开发多端小程序+H5',
           target: 'target6',
           target: 'target6',
           popoverOffset: [40, 12],
           popoverOffset: [40, 12],
           arrowOffset: -36
           arrowOffset: -36
@@ -183,7 +184,7 @@ export default {
 
 
       steps3: [
       steps3: [
         {
         {
-          content: '邀请有礼,全新改版,奖励多多哦',
+          content: '70+ 高质量组件,覆盖移动端主流场景',
           target: 'target7'
           target: 'target7'
         }
         }
       ],
       ],