123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <template>
- <view class="guide-manager">
- <!-- 遮罩层 -->
- <view class="guide-mask" v-if="currentStage" @click="handleMaskClick">
- <!-- 高亮区域 -->
- <view class="highlight-area" :style="highlightStyle"></view>
-
- <!-- 提示框 -->
- <view class="guide-tips" :style="tipsStyle">
- <view class="tips-content">
- <text class="tips-text">{{ currentStep.tips }}</text>
- <view class="tips-buttons">
- <text class="skip-btn" @click.stop="skipStage">跳过</text>
- <text class="next-btn" @click.stop="nextStep">{{ isLastStep ? '完成' : '下一步' }}</text>
- </view>
- </view>
- <!-- 箭头 -->
- <view class="arrow" :style="arrowStyle"></view>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- name: 'GuideManager',
- data() {
- return {
- // 当前引导阶段
- currentStage: null,
- // 当前步骤索引
- currentStepIndex: 0,
- // 已完成阶段
- completedStages: [],
- // 引导配置
- guideConfig: {
- // 主岛引导
- mainLand: {
- id: 'mainLand',
- steps: [
- {
- target: '.house-image',
- tips: '这是你的房屋,点击可以进入查看',
- position: 'bottom'
- },
- {
- target: '.farm-image',
- tips: '这是农场,可以种植作物',
- position: 'bottom'
- },
- {
- target: '.shop-image',
- tips: '这是商店,可以购买物品',
- position: 'bottom'
- }
- ]
- },
- // 家园引导
- homeLand: {
- id: 'homeLand',
- steps: [
- {
- target: '.house-image',
- tips: '这是你的家,点击可以进入',
- position: 'bottom'
- },
- {
- target: '.table-image',
- tips: '这是工作台,可以制作物品',
- position: 'bottom'
- },
- {
- target: '.taskBoard-image',
- tips: '这是任务板,可以查看任务',
- position: 'bottom'
- }
- ]
- }
- }
- }
- },
- computed: {
- // 当前步骤
- currentStep() {
- if (!this.currentStage) return null
- return this.currentStage.steps[this.currentStepIndex]
- },
- // 是否是最后一步
- isLastStep() {
- if (!this.currentStage) return false
- return this.currentStepIndex === this.currentStage.steps.length - 1
- },
- // 高亮区域样式
- highlightStyle() {
- if (!this.currentStep) return {}
- return this.currentStep.rect ? {
- top: `${this.currentStep.rect.top}px`,
- left: `${this.currentStep.rect.left}px`,
- width: `${this.currentStep.rect.width}px`,
- height: `${this.currentStep.rect.height}px`
- } : {}
- },
- // 提示框样式
- tipsStyle() {
- if (!this.currentStep || !this.currentStep.rect) return {}
-
- const rect = this.currentStep.rect
- const position = this.currentStep.position
- const systemInfo = uni.getSystemInfoSync()
-
- let style = {}
- switch (position) {
- case 'top':
- style = {
- bottom: `${systemInfo.windowHeight - rect.top + 10}px`,
- left: `${rect.left + rect.width / 2}px`,
- transform: 'translateX(-50%)'
- }
- break
- case 'bottom':
- style = {
- top: `${rect.bottom + 10}px`,
- left: `${rect.left + rect.width / 2}px`,
- transform: 'translateX(-50%)'
- }
- break
- case 'left':
- style = {
- top: `${rect.top + rect.height / 2}px`,
- right: `${systemInfo.windowWidth - rect.left + 10}px`,
- transform: 'translateY(-50%)'
- }
- break
- case 'right':
- style = {
- top: `${rect.top + rect.height / 2}px`,
- left: `${rect.right + 10}px`,
- transform: 'translateY(-50%)'
- }
- break
- }
-
- return style
- },
- // 箭头样式
- arrowStyle() {
- if (!this.currentStep) return {}
- const position = this.currentStep.position
-
- let style = {}
- switch (position) {
- case 'top':
- style = {
- transform: 'rotate(180deg)',
- bottom: '0'
- }
- break
- case 'bottom':
- style = {
- transform: 'rotate(0deg)',
- top: '0'
- }
- break
- case 'left':
- style = {
- transform: 'rotate(90deg)',
- right: '0'
- }
- break
- case 'right':
- style = {
- transform: 'rotate(-90deg)',
- left: '0'
- }
- break
- }
-
- return style
- }
- },
- methods: {
- // 开始引导
- startGuide(stageId) {
- // 检查是否已完成
- if (this.completedStages.includes(stageId)) {
- return
- }
-
- // 设置当前阶段
- this.currentStage = this.guideConfig[stageId]
- this.currentStepIndex = 0
-
- // 等待DOM更新后更新位置
- this.$nextTick(() => {
- this.updatePositions()
- })
- },
- // 下一步
- nextStep() {
- if (this.isLastStep) {
- this.completeStage()
- } else {
- this.currentStepIndex++
- this.$nextTick(() => {
- this.updatePositions()
- })
- }
- },
- // 跳过当前阶段
- skipStage() {
- this.completeStage()
- },
- // 完成当前阶段
- completeStage() {
- if (this.currentStage) {
- // 添加到已完成列表
- this.completedStages.push(this.currentStage.id)
- // 保存到本地存储
- this.saveCompletedStages()
- // 重置状态
- this.currentStage = null
- this.currentStepIndex = 0
- }
- },
- // 更新位置
- updatePositions() {
- if (!this.currentStep) return
-
- const query = uni.createSelectorQuery().in(this)
- query.select(this.currentStep.target).boundingClientRect(data => {
- if (data) {
- // 更新当前步骤的位置信息
- this.$set(this.currentStage.steps[this.currentStepIndex], 'rect', data)
- }
- }).exec()
- },
- // 保存已完成阶段
- saveCompletedStages() {
- uni.setStorageSync('completedGuideStages', this.completedStages)
- },
- // 加载已完成阶段
- loadCompletedStages() {
- const stages = uni.getStorageSync('completedGuideStages')
- if (stages) {
- this.completedStages = stages
- }
- },
- // 处理遮罩层点击
- handleMaskClick() {
- // 可以在这里添加点击遮罩层的处理逻辑
- }
- },
- mounted() {
- // 加载已完成阶段
- this.loadCompletedStages()
- }
- }
- </script>
- <style lang="scss" scoped>
- .guide-manager {
- .guide-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.7);
- z-index: 9999;
-
- .highlight-area {
- position: absolute;
- box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
- border-radius: 4px;
- transition: all 0.3s ease;
- }
-
- .guide-tips {
- position: absolute;
- background: #fff;
- border-radius: 8px;
- padding: 16px;
- min-width: 200px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- transition: all 0.3s ease;
-
- .tips-content {
- .tips-text {
- font-size: 14px;
- color: #333;
- line-height: 1.5;
- margin-bottom: 12px;
- }
-
- .tips-buttons {
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .skip-btn,
- .next-btn {
- font-size: 14px;
- padding: 4px 12px;
- border-radius: 4px;
- cursor: pointer;
- }
-
- .skip-btn {
- color: #999;
- }
-
- .next-btn {
- color: #fff;
- background-color: #1890ff;
- }
- }
- }
-
- .arrow {
- position: absolute;
- width: 0;
- height: 0;
- border: 8px solid transparent;
- border-bottom-color: #fff;
- }
- }
- }
- }
- </style>
|