uniapp入门到进阶 一 4、uniapp工程全栈结构划分

uniapp入门到进阶 一 4、uniapp工程全栈结构划分上一小节我们详细讲述了 uni-app全栈开发vite环境及插件配置管理 。接下来我们需要对我们的项目工程 uniapp-demo 做一个结构划

大家好,欢迎来到IT知识分享网。uniapp入门到进阶

上一小节我们详细讲述了 uni-app全栈开发vite环境及插件配置管理。接下来我们需要对我们的项目工程 uniapp-demo 做一个结构划分,分类存放我们的工程文件

1、自动注入全局 API ,避免繁琐的API引入

//根目录创建declare文件,存放auto-imports.d.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:52:03
 * @Description: 自动注入全局API
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
declare global {
  const app: typeof import('@/app/index')['app']
  const assert: typeof import('power-assert')['default']
  const computed: typeof import('vue')['computed']
  const createApp: typeof import('vue')['createApp']
  const customRef: typeof import('vue')['customRef']
  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
  const defineComponent: typeof import('vue')['defineComponent']
  const effectScope: typeof import('vue')['effectScope']
  const EffectScope: typeof import('vue')['EffectScope']
  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
  const getCurrentScope: typeof import('vue')['getCurrentScope']
  const h: typeof import('vue')['h']
  const inject: typeof import('vue')['inject']
  const isReadonly: typeof import('vue')['isReadonly']
  const isRef: typeof import('vue')['isRef']
  const markRaw: typeof import('vue')['markRaw']
  const nextTick: typeof import('vue')['nextTick']
  const onActivated: typeof import('vue')['onActivated']
  const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
  const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
  const onBeforeMount: typeof import('vue')['onBeforeMount']
  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
  const onDeactivated: typeof import('vue')['onDeactivated']
  const onError: typeof import('@dcloudio/uni-app')['onError']
  const onErrorCaptured: typeof import('vue')['onErrorCaptured']
  const onHide: typeof import('@dcloudio/uni-app')['onHide']
  const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
  const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
  const onMounted: typeof import('vue')['onMounted']
  const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
  const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
  const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
  const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
  const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
  const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
  const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
  const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
  const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
  const onReady: typeof import('@dcloudio/uni-app')['onReady']
  const onRenderTracked: typeof import('vue')['onRenderTracked']
  const onRenderTriggered: typeof import('vue')['onRenderTriggered']
  const onResize: typeof import('@dcloudio/uni-app')['onResize']
  const onScopeDispose: typeof import('vue')['onScopeDispose']
  const onServerPrefetch: typeof import('vue')['onServerPrefetch']
  const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
  const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
  const onShow: typeof import('@dcloudio/uni-app')['onShow']
  const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
  const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
  const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
  const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
  const onUnmounted: typeof import('vue')['onUnmounted']
  const onUpdated: typeof import('vue')['onUpdated']
  const provide: typeof import('vue')['provide']
  const reactive: typeof import('vue')['reactive']
  const readonly: typeof import('vue')['readonly']
  const ref: typeof import('vue')['ref']
  const resolveComponent: typeof import('vue')['resolveComponent']
  const ScrollSymbol: typeof import('@/hooks')['ScrollSymbol']
  const shallowReactive: typeof import('vue')['shallowReactive']
  const shallowReadonly: typeof import('vue')['shallowReadonly']
  const shallowRef: typeof import('vue')['shallowRef']
  const toRaw: typeof import('vue')['toRaw']
  const toRef: typeof import('vue')['toRef']
  const toRefs: typeof import('vue')['toRefs']
  const triggerRef: typeof import('vue')['triggerRef']
  const unref: typeof import('vue')['unref']
  const useAttrs: typeof import('vue')['useAttrs']
  const useCssModule: typeof import('vue')['useCssModule']
  const useCssVars: typeof import('vue')['useCssVars']
  const useQuery: typeof import('@/hooks')['useQuery']
  const useScroll: typeof import('@/hooks')['useScroll']
  const useSlots: typeof import('vue')['useSlots']
  const watch: typeof import('vue')['watch']
  const watchEffect: typeof import('vue')['watchEffect']
}
export {}

//注意:在上一节 imports.config.ts 文件导出全局配置
dts: 'declare/auto-imports.d.ts',

2、完善src文件工程结构

src下创建store文件,并完善工程文件(状态管理

//新建src/store/index.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:04:03
 * @Description: 请求封装
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import { InjectionKey} from 'vue'
import { createStore } from 'vuex'
import { store as app, AppState, AppStore } from '@/store/modules/app'
import getters from './getters'

export const key: InjectionKey<Store> = Symbol()
export interface RootState {
  app: AppState
}
export type Store = AppStore<Pick<RootState, 'app'>>

export const store = createStore<RootState>({ 
  modules: {
    app
  },
  getters
})

export function useStore(): Store {
  return store as Store
}
//新建src/store/getters.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:15:22
 * @Description: 请求封装
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import { RootState } from '@/store'
export default {
  token: (state: RootState) => state.app.token,
}
//新建modules src/store/modules/app/index.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:19:59
 * @Description: 请求封装
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import { Store as VuexStore, CommitOptions, DispatchOptions, Module } from 'vuex'
import { RootState } from '@/store'
import { state } from './state'
import { actions, Actions } from './ations'
import { mutations, Mutations } from './mutations'
import type { AppState } from './state'

export { AppState }

export type AppStore<S = AppState> = Omit<VuexStore<S>, 'getters' | 'commit' | 'dispatch'> & {
  commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
    key: K,
    payload: P,
    options?: CommitOptions
  ): ReturnType<Mutations[K]>
} & {
  dispatch<K extends keyof Actions>(
    key: K,
    payload: Parameters<Actions[K]>[1],
    options?: DispatchOptions
  ): ReturnType<Actions[K]>
}

export const store: Module<AppState, RootState> = {
  state,
  actions,
  mutations,
}
//新建modules src/store/modules/app/state.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:19:59
 * @Description: state
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import {reactive} from 'vue'
export interface AppState {
  token: string,
  num:number,
  userData: Array<any>
}

export const state: AppState = reactive({
  token: '',
  num:0,
  userData:{}
}) 
//新建modules src/store/modules/app/action-types.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:22:12
 * @Description:  action-types类型约束
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
export enum AppActionTypes {
  ACTION_LOGIN = 'ACTION_LOGIN',
  CLEAR_TOKEN = 'CLEAR_TOKEN',
  EDIT_USER_MSG = 'EDIT_USER_MSG',
  SET_NUM = 'SET_NUM'
}
//新建modules src/store/modules/app/action.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:20:58
 * @Description: action
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import { ActionTree, ActionContext } from 'vuex'
import { RootState } from '@/store'
import { AppState } from './state'
import { Mutations } from './mutations'
import { AppActionTypes } from './action-types'
import { AppMutationTypes } from './mutation-types'

type AugmentedActionContext = {
  commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>
} & Omit<ActionContext<AppState, RootState>, 'commit'>

// export interface Actions {
//   [AppActionTypes.ACTION_RESET_TOKEN]({ commit }: AugmentedActionContext): void
// }

export const actions: ActionTree<AppState, RootState> & Actions = {
  [AppActionTypes.ACTION_LOGIN]({ commit }: AugmentedActionContext, userData: object) {
    commit(AppMutationTypes.SET_USER_MSG, userData)
  },
  [AppActionTypes.CLEAR_TOKEN]({ commit }: AugmentedActionContext) {
    commit(AppMutationTypes.CLEAR_USER, null)
  },
  [AppActionTypes.CLEAR_TOKEN]({ commit }: AugmentedActionContext,userData: object) {
    commit(AppMutationTypes.CLEAR_TOKEN, userData)
  },
 [AppActionTypes.SET_NUM]({ commit }: AugmentedActionContext,num: number) {
   commit(AppMutationTypes.SET_NUM, num)
 },
  
 
}
//新建modules src/store/modules/app/mutation-types.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:22:12
 * @Description:  mutation-types类型约束
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
export enum AppMutationTypes {
  SET_USER_MSG = 'SET_USER_MSG',
  CLEAR_TOKEN = 'CLEAR_TOKEN',
  EDIT_USER_MSG = 'EDIT_USER_MSG',
  SET_NUM = 'SET_NUM'
}

//新建modules src/store/modules/app/mutation.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:22:12
 * @Description:  mutation
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import { MutationTree } from 'vuex'
import { AppState } from './state'
import { AppMutationTypes } from './mutation-types'

export type Mutations<S = AppState> = {
  [AppMutationTypes.SET_TOKEN](state: S, token: string): void
}
export const mutations: MutationTree<AppState> & Mutations = {
  [AppMutationTypes.SET_USER_MSG](state: AppState, userData: object) {
	state.userData = userData
  },
  [AppMutationTypes.CLEAR_USER](state: AppState) {
	state.userData = null
  },
  [AppMutationTypes.CLEAR_TOKEN](state: AppState, userData: object) {
	state.userData = userData
  },
  [AppMutationTypes.SET_NUM](state: AppState, num: number) {
  	state.num = num
  }
  
  
  
}

src下创建type文件,并完善工程文件(约束类

//例如:分页参数,根据业务需要自行补充
export interface PageParams {
  data?: any
  id?: string
  from?: string
}

src下创建styles文件,并完善工程文件(css样式)

//例如:styles/theme.scss
page {
  --theme-color: #9ac2ff;
}

//例如:styles/index.scss
@import './theme.scss'; //引入theme.scss

src下创建components文件,并完善工程文件(组件管理

//例如:components/drag-image.vue
<template>
  <view class="con">
    <template v-if="viewWidth">
      <movable-area v-if="show" class="area" :style="{ height: areaHeight }" @mouseenter="mouseenter"
        @mouseleave="mouseleave">
		<text v-if='imageList.length>0' class="tips_img">主</text>
        <movable-view v-for="(item, index) in imageList" :key="item.id" class="view" direction="all" :y="item.y"
          :x="item.x" :damping="40" :disabled="item.disable" @change="onChange($event, item)"
          @touchstart="touchstart(item)" @mousedown="touchstart(item)" @touchend="touchend(item)"
          @mouseup="touchend(item)" :style="{
            width: viewWidth + 'px',
            height: viewWidth + 'px',
            'z-index': item.zIndex,
            opacity: item.opacity
          }">
          <view class="area-con" :style="{
            width: childWidth,
            height: childWidth,
            borderRadius: borderRadius + 'rpx',
            transform: 'scale(' + item.scale + ')'
          }">
            <image class="pre-image" :src="item.src" mode="aspectFill"></image>
			
            <view class="del-con" @click="delImages(item, index)" @touchstart.stop="delImageMp(item, index)"
              @touchend.stop="nothing()" @mousedown.stop="nothing()" @mouseup.stop="nothing()">
              <view class="del-wrap">
                <image class="del-image"
                  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAhdEVYdENyZWF0aW9uIFRpbWUAMjAyMDowNzoyNSAyMTo1NDoyOU4TkJAAAADcSURBVFhH7ZfRCoMwDEXLvkjwwVf/bH/emmAyN6glTW9WBjsgwm28OeCLpj81Sil7zvlJ90UiONS/yY5VogsO6XrBg3IEQ5a/s8vRSWUAKmLqp2w5jz5BiNQEGMo3GbloDLtFXJ1IkaEuhAiiY6gEIqB4yqACSk9piIBiKQ8VUFpLviKg3C2rESKgWERCBZSWiEfgIfffYvrrsAgoISJ3Apy3zuTxcSxLQkV6ykNEPKVQkZEyiAiiZKgDIaC4upACSlcn5fM/+WuDCAHF1E/Z/N9AhkMZnPNDPI+UDjPIXgAQIGjNAAAAAElFTkSuQmCC">
                </image>
              </view>
            </view>
          </view>
        </movable-view>
        <view class="add" v-if="imageList.length < number"
          :style="{ top: add.y, left: add.x, width: viewWidth + 'px', height: viewWidth + 'px' }" @click="addImages">
          <view class="add-wrap" :style="{ width: childWidth, height: childWidth, borderRadius: borderRadius + 'rpx' }">
           	<image  :style="{ width: childWidth, height: childWidth, borderRadius: borderRadius + 'rpx' }"  src='/static/images/addimg.png'></image>
			<!-- <image style="width: 54rpx;height: 54rpx;"
              src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAAA2CAYAAACMRWrdAAABIUlEQVRoQ+2a2w2DMAxFeQzWrsMUbadAsEw3S1CqVgppKwLX8BEOP4iHTXx8uUgWdVXoVhdaV0VhSmf7vr/H8V3XzY6V3P9iD+nYOI5P7/01LMI596AwoZV0TIBXIUWFXhKLFBWYSFGhhxQN6SFFQ5i4ogITKSr0cEVDekjRECauqMBEigq9U7piOk2yAti27SUe5ljlTfPEQ6KZecTvwl4P3ytvOv06R2HDMNzes7+6aRrvnHvtf50L13Lp50rx88zcvNlS3JpwKQ67XyK04nq2nFbk/LqVjin0TvmBNgQ2S4UUDcliHgpMpKjQwxUN6SFFQ5i4ogITKSr0cEVDekjRECauqMAsVoph+hVPtYr5+03p9tbYQ96xrYtT4ootbAJGVxxVTapVswAAAABJRU5ErkJggg==">
            </image> -->
          </view>
        </view>
      </movable-area>

    </template>
  </view>
</template>

<script>
export default {
  emits: ['input', 'update:modelValue'],
  props: {
    // 排序图片
    value: {
      type: Array,
      default: function () {
        return []
      }
    },
    // 排序图片
    modelValue: {
      type: Array,
      default: function () {
        return []
      }
    },
    // 从 list 元素对象中读取的键名
    keyName: {
      type: String,
      default: null
    },
    // 选择图片数量限制
    number: {
      type: Number,
      default: 6
    },
    // 图片父容器宽度(实际显示的图片宽度为 imageWidth / 1.1 ),单位 rpx
    // imageWidth > 0 则 cols 无效
    imageWidth: {
      type: Number,
      default: 0
    },
    // 图片列数
    cols: {
      type: Number,
      default: 3
    },
    // 图片圆角,单位 rpx
    borderRadius: {
      type: Number,
      default: 0
    },
    // 图片周围空白填充,单位 rpx
    padding: {
      type: Number,
      default: 10
    },
    // 拖动图片时放大倍数 [0, ∞)
    scale: {
      type: Number,
      default: 1.1
    },
    // 拖动图片时不透明度
    opacity: {
      type: Number,
      default: 0.7
    },
    // 自定义添加
    addImage: {
      type: Function,
      default: null
    },
    // 删除确认
    delImage: {
      type: Function,
      default: null
    }
  },
  data() {
    return {
      imageList: [],
      width: 0,
      add: {
        x: 0,
        y: 0
      },
      colsValue: 0,
      viewWidth: 0,
      tempItem: null,
      timer: null,
      changeStatus: true,
      preStatus: true,
      first: true,
      show: true,
    }
  },
  computed: {
    areaHeight() {
      let height = ''
      // return '285px'
      if (this.imageList.length < this.number) {
        height = (Math.ceil((this.imageList.length + 1) / this.colsValue) * this.viewWidth).toFixed() + 'px'
      } else {
        height = (Math.ceil(this.imageList.length / this.colsValue) * this.viewWidth).toFixed() + 'px'
      }
      console.log('areaHeight', height)
      return height
    },
    childWidth() {
      return this.viewWidth - this.rpx2px(this.padding) * 2 + 'px'
    },
  },
  watch: {
    areaHeight() {
      this.show = false
      this.$nextTick(() => {
        this.show = true
      })
    },
    value: {
      handler(n) {
        if (!this.first && this.changeStatus) {
          console.log('watch', n)
          let flag = false
          for (let i = 0; i < n.length; i++) {
            if (flag) {
              this.addProperties(this.getSrc(n[i]))
              continue
            }
            if (this.imageList.length === i || this.imageList[i].src !== this.getSrc(n[i])) {
              flag = true
              this.imageList.splice(i)
              this.addProperties(this.getSrc(n[i]))
            }
          }
        }
      },
      deep: true
    },
    modelValue: {
      handler(n) {
        if (!this.first && this.changeStatus) {
          console.log('watch', n)
          let flag = false
          for (let i = 0; i < n.length; i++) {
            if (flag) {
              this.addProperties(this.getSrc(n[i]))
              continue
            }
            if (this.imageList.length === i || this.imageList[i].src !== this.getSrc(n[i])) {
              flag = true
              this.imageList.splice(i)
              this.addProperties(this.getSrc(n[i]))
            }
          }
        }
      },
      deep: true
    },
  },
  created() {
    this.width = uni.getSystemInfoSync().windowWidth
  },
  mounted() {
    const query = uni.createSelectorQuery().in(this)
    query.select('.con').boundingClientRect(data => {
      this.colsValue = this.cols
      this.viewWidth = data.width / this.cols
      if (this.imageWidth > 0) {
        this.viewWidth = this.rpx2px(this.imageWidth)
        this.colsValue = Math.floor(data.width / this.viewWidth)
      }
      let list = this.value
      // #ifdef VUE3
      list = this.modelValue
      // #endif
      for (let item of list) {
        this.addProperties(this.getSrc(item))
      }
      this.first = false

    })
    query.exec()
  },
  methods: {
    getSrc(item) {
      if (this.keyName !== null) {
        return item[this.keyName]
      }
      return item
    },
    onChange(e, item) {
      if (!item) return
      item.oldX = e.detail.x
      item.oldY = e.detail.y
      if (e.detail.source === 'touch') {
        if (item.moveEnd) {
          item.offset = Math.sqrt(Math.pow(item.oldX - item.absX * this.viewWidth, 2) + Math.pow(item.oldY - item
            .absY * this.viewWidth, 2))
        }
        let x = Math.floor((e.detail.x + this.viewWidth / 2) / this.viewWidth)
        if (x >= this.colsValue) return
        let y = Math.floor((e.detail.y + this.viewWidth / 2) / this.viewWidth)
        let index = this.colsValue * y + x
        if (item.index != index && index < this.imageList.length) {
          this.changeStatus = false
          for (let obj of this.imageList) {
            if (item.index > index && obj.index >= index && obj.index < item.index) {
              this.change(obj, 1)
            } else if (item.index < index && obj.index <= index && obj.index > item.index) {
              this.change(obj, -1)
            } else if (obj.id != item.id) {
              obj.offset = 0
              obj.x = obj.oldX
              obj.y = obj.oldY
              setTimeout(() => {
                this.$nextTick(() => {
                  obj.x = obj.absX * this.viewWidth
                  obj.y = obj.absY * this.viewWidth
                })
              }, 0)
            }
          }
          item.index = index
          item.absX = x
          item.absY = y
          if (!item.moveEnd) {
            setTimeout(() => {
              this.$nextTick(() => {
                item.x = item.absX * this.viewWidth
                item.y = item.absY * this.viewWidth
              })
            }, 0)
          }
          // console.log('bbb', JSON.parse(JSON.stringify(item)));
          this.sortList()
        }
      }
    },
    change(obj, i) {
      obj.index += i
      obj.offset = 0
      obj.x = obj.oldX
      obj.y = obj.oldY
      obj.absX = obj.index % this.colsValue
      obj.absY = Math.floor(obj.index / this.colsValue)
      setTimeout(() => {
        this.$nextTick(() => {
          obj.x = obj.absX * this.viewWidth
          obj.y = obj.absY * this.viewWidth
        })
      }, 0)
    },
    touchstart(item) {
      this.imageList.forEach(v => {
        v.zIndex = v.index + 9
      })
      item.zIndex = 99
      item.moveEnd = true
      this.tempItem = item
      this.timer = setTimeout(() => {
        item.scale = this.scale
        item.opacity = this.opacity
        clearTimeout(this.timer)
        this.timer = null
      }, 200)
    },
    touchend(item) {
      this.previewImage(item)
      item.scale = 1
      item.opacity = 1
      item.x = item.oldX
      item.y = item.oldY
      item.offset = 0
      item.moveEnd = false
      setTimeout(() => {
        this.$nextTick(() => {
          item.x = item.absX * this.viewWidth
          item.y = item.absY * this.viewWidth
          this.tempItem = null
          this.changeStatus = true
        })
        // console.log('ccc', JSON.parse(JSON.stringify(item)));
      }, 0)
	   this.$emit('resetImg',this.imageList)
      // console.log('ddd', JSON.parse(JSON.stringify(item)));
    },
    previewImage(item) {
      if (this.timer && this.preStatus && this.changeStatus && item.offset < 28.28) {
        clearTimeout(this.timer)
        this.timer = null
        const list = this.value || this.modelValue
        let srcList = []
		let numImg = ref(0)
		this.imageList.map((tab, index) => {
			srcList.push(item.src)
			if(tab.src ==  item.src){
				numImg.value = index
			}
		})
		
        uni.previewImage({
          urls:srcList ,
          current: srcList[numImg],
          success: () => {
            this.preStatus = false
            setTimeout(() => {
              this.preStatus = true
            }, 600)
          },
          fail: (e) => {
            console.log(e);
          }
        })
      } else if (this.timer) {
        clearTimeout(this.timer)
        this.timer = null
      }
    },
    mouseenter() {
      //#ifdef H5
      this.imageList.forEach(v => {
        v.disable = false
      })
      //#endif

    },
    mouseleave() {
      //#ifdef H5
      if (this.tempItem) {
        this.imageList.forEach(v => {
          v.disable = true
          v.zIndex = v.index + 9
          v.offset = 0
          v.moveEnd = false
          if (v.id == this.tempItem.id) {
            if (this.timer) {
              clearTimeout(this.timer)
              this.timer = null
            }
            v.scale = 1
            v.opacity = 1
            v.x = v.oldX
            v.y = v.oldY
            this.$nextTick(() => {
              v.x = v.absX * this.viewWidth
              v.y = v.absY * this.viewWidth
              this.tempItem = null
            })
          }
        })
        this.changeStatus = true
      }
      //#endif
    },
    addImages() {
		this.$emit('choiseImg')
      // if (typeof this.addImage === 'function') {
      //   this.addImage.bind(this.$parent)()
      // } else {
      //   let checkNumber = this.number - this.imageList.length
      //   uni.chooseImage({
      //     count: checkNumber,
      //     sourceType: ['album', 'camera'],
      //     success: res => {
      //       let count = checkNumber <= res.tempFilePaths.length ? checkNumber : res.tempFilePaths.length
      //       for (let i = 0; i < count; i++) {
      //         this.addProperties(res.tempFilePaths[i])
      //       }
      //       this.sortList()
      //     }
      //   })
      // }
    },
    delImages(item, index) {
      if (typeof this.delImage === 'function') {
        this.delImage.bind(this.$parent)(() => {
          this.delImageHandle(item, index)
        })
      } else {
        this.delImageHandle(item, index)
      }
    },
    delImageHandle(item, index) {
      this.imageList.splice(index, 1)
	  this.$emit('resetImg',this.imageList)
      for (let obj of this.imageList) {
        if (obj.index > item.index) {
          obj.index -= 1
          obj.x = obj.oldX
          obj.y = obj.oldY
          obj.absX = obj.index % this.colsValue
          obj.absY = Math.floor(obj.index / this.colsValue)
          this.$nextTick(() => {
            obj.x = obj.absX * this.viewWidth
            obj.y = obj.absY * this.viewWidth
          })
        }
      }
      this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'
      this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'
      this.sortList()
    },
    delImageMp(item, index) {
      //#ifdef MP
      this.delImages(item, index)
      //#endif
    },
    sortList() {
      console.log('sortList');
      const result = []
      let source = this.value
      // #ifdef VUE3
      source = this.modelValue
      // #endif

      let list = this.imageList.slice()
      list.sort((a, b) => {
        return a.index - b.index
      })
      for (let s of list) {
        let item = source.find(d => this.getSrc(d) == s.src)
        if (item) {
          result.push(item)
        } else {
          if (this.keyName !== null) {
            result.push({
              [this.keyName]: s.src
            })
          } else {
            result.push(s.src)
          }
        }
      }

      this.$emit("input", result);
      this.$emit("update:modelValue", result);
    },
    addProperties(item) {
      console.log(item);
      let absX = this.imageList.length % this.colsValue
      let absY = Math.floor(this.imageList.length / this.colsValue)
      let x = absX * this.viewWidth
      let y = absY * this.viewWidth
      this.imageList.push({
        src: item,
        x,
        y,
        oldX: x,
        oldY: y,
        absX,
        absY,
        scale: 1,
        zIndex: 9,
        opacity: 1,
        index: this.imageList.length,
        id: this.guid(16),
        disable: false,
        offset: 0,
        moveEnd: false
      })
      this.add.x = (this.imageList.length % this.colsValue) * this.viewWidth + 'px'
      this.add.y = Math.floor(this.imageList.length / this.colsValue) * this.viewWidth + 'px'
    },
    nothing() { },
    rpx2px(v) {
      return this.width * v / 750
    },
    guid(len = 32) {
      const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
      const uuid = []
      const radix = chars.length
      for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
      uuid.shift()
      return `u${uuid.join('')}`
    }
  }
}
</script>

<style lang="scss" scoped>
.con {
  // padding: 30rpx;

  .area {
    width: 100%;
	position: relative;
	.tips_img{
		position: absolute;
		left:0rpx;
		top:0rpx;
		z-index: 999;
		display: inline-block;
		width:42rpx;
		height:42rpx;
		line-height: 42rpx;
		text-align: center;
		border-radius: 50%;
		font-size: 20rpx;
		background-color: rgba(0,0,0,.5);
		color:#fff;
	}
    .view {
      display: flex;
      justify-content: center;
      align-items: center;

      .area-con {
        position: relative;
        overflow: hidden;
		.tips_img{
			position: absolute;
			right:0rpx;
			bottom:0rpx;
			z-index: 999;
			display: inline-block;
			width:42rpx;
			height:42rpx;
			line-height: 42rpx;
			text-align: center;
			border-radius: 50%;
			font-size: 20rpx;
			background-color: rgba(0,0,0,.5);
			color:#fff;
			
		}
        .pre-image {
          width: 100%;
          height: 100%;
        }

        .del-con {
          position: absolute;
          top: 0rpx;
          right: 0rpx;
          padding: 0 0 20rpx 20rpx;

          .del-wrap {
            width: 36rpx;
            height: 36rpx;
            background-color: rgba(0, 0, 0, 0.4);
            border-radius: 0 0 0 10rpx;
            display: flex;
            justify-content: center;
            align-items: center;

            .del-image {
              width: 20rpx;
              height: 20rpx;
            }
          }
        }
      }
    }

    .add {
      position: absolute;
      display: flex;
      justify-content: center;
      align-items: center;

      .add-wrap {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: #fff;
      }
    }
  }
}
</style>

src下创建utils文件,并完善工程文件(工具类

//新建src/utils/requestClass.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:59:03
 * @Description: 请求封装requestClass类
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
const config = Symbol('config')
const isCompleteURL = Symbol('isCompleteURL')
const requestBefore = Symbol('requestBefore')
const requestAfter = Symbol('requestAfter')

class requestClass {
  // 默认配置
  [config]: { baseURL?: string } & UniApp.RequestOptions = {
    baseURL: '',
    url: '',
    header: {
      'content-type': 'application/x-www-form-urlencoded'
    },
    method: 'GET',
    timeout: 3000,
    dataType: 'json',
    responseType: 'text'
  }

  // 拦截器
  interceptors = {
    request: (func: Fn) => {
      if (func) {
        requestClass[requestBefore] = func
      } else {
        requestClass[requestBefore] = (request) => request
      }
    },
    response: (func: Fn) => {
      if (func) {
        requestClass[requestAfter] = func
      } else {
        requestClass[requestAfter] = (response) => response
      }
    },
  }

  // 请求之前,是默认配置
  static [requestBefore](config: UniApp.RequestOptions) {
    return config
  }
  // 请求之后,默认配置发生改变的话
  static [requestAfter](response: any) {
    return response
  }
  // 判断url是否完整
  static [isCompleteURL](url: string) {
    return /(http|https):\/\/([\w.]+\/?)\S*/.test(url)
  }

  request(options: UniApp.RequestOptions & { baseURL?: string }) {
    options.baseURL = options.baseURL || this[config].baseURL
    options.dataType = options.dataType || this[config].dataType
    options.url = requestClass[isCompleteURL](options.url) ? options.url : (options.baseURL + options.url)
	
    options.data = options.data
    options.header = { ...options.header, ...this[config].header }
    options.method = options.method || this[config].method

    options = { ...options, ...requestClass[requestBefore](options) }

    return new Promise((resolve, reject) => {
      options.success = function (res) {
        resolve(requestClass[requestAfter](res))
      }
      options.fail = function (err) {
        reject(requestClass[requestAfter](err))
      }
      uni.request(options)
      // 中断请求实现方法
      // let obj: any = {}
      // obj[request.url] = uni.request(options)
      // abortRequest() {
      //   for (const key in obj) {
      //     if (Object.prototype.hasOwnProperty.call(obj, key)) {
      //       const element = obj[key];
      //       element.abort()
      //     }
      //   }
      // }
    })
  }

  get(url: string, data: any = {}, options: Recordable = {}) {
    return this.request({ ...options, url, data, method: 'GET' })
  }

  post(url: string, data: any = {}, options: Recordable = {}) {
    return this.request({ ...options, url, data, method: 'POST' })
  }

  put(url: string, data: any = {}, options: Recordable = {}) {
    return this.request({ ...options, url, data, method: 'PUT' })
  }

  delete(url: string, data: any = {}, options: Recordable = {}) {
    return this.request({ ...options, url, data, method: 'DELETE' })
  }

  getConfig() {
    return this[config]
  }
  
  // 修改默认配置的一个方法,可以修改请求地址,请求方式等等..
  setConfig(func: Fn) {
    this[config] = func(this[config])
  }
}

export default requestClass
//新建src/utils/request.ts
/**
 * @Author: Mr Chen  陈晓 
 * @Date: 2023-01-16 14:12:05
 * @LastEditTime: 2023-02-09 09:59:03
 * @Description: 请求封装request
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 **/
import requestClass from './requestClass'
import { HTTP_REQUEST_URL_H5, HTTP_REQUEST_URL_APP } from '@/config/app'
import { AppActionTypes } from '@/store/modules/app/action-types'
import qs from 'qs'
import { useStore } from 'vuex'

const Request = new requestClass()
const platform = uni.getSystemInfoSync().platform

// 请求拦截器
Request.interceptors.request((request: any) => {
	request.header['device-os'] = platform
	
  if (request.header.contentType) {
    request.header['content-type'] = request.header.contentType
    delete request.header.contentType
  }
  if(uni.getStorageSync('userData')){
	request.header['token'] = uni.getStorageSync('userData').token
	// request.header['id'] = uni.getStorageSync('userData').id
	// request.header['uid'] = uni.getStorageSync('userData').userIdBuss
	// request.header['pid'] = uni.getStorageSync('userData').lmpt_userid
  }
  if (request.method === 'GET') {
    request.data = qs.stringify(request.data)
    request.url = request.url + '?' + request.data
  }
  return request
})

// 响应拦截器
Request.interceptors.response((response: any) => {
  const token = uni.getStorageSync('userData').token
  if (response.data.code === 102) {
    uni.showToast({
      title: token ? '请重新登录' : '请先登录',
      icon: 'none',
      duration: 2000,
    })
   
    uni.removeStorageSync('userData')
	// console.log(store)
	// store.dispatch(AppActionTypes.ACTION_LOGIN, {})
	const url = '/pages/template/user/index'
	setTimeout(
		function() {
			uni.switchTab({ url })
		}, 2000)
  }
  return response
})

// 设置默认配置
Request.setConfig((config: any) => {
	config.header['device-os'] = platform
	// #ifdef APP-PLUS
	config.baseURL = HTTP_REQUEST_URL_APP
	// #endif
	// #ifndef APP-PLUS
	config.baseURL = HTTP_REQUEST_URL_H5
	// #endif
  if (uni.getStorageSync('userData')) {
    config.header['token'] = uni.getStorageSync('userData').token
	// config.header['id'] = uni.getStorageSync('userData').id
	// config.header['uid'] = uni.getStorageSync('userData').userIdBuss
	// config.header['pid'] = uni.getStorageSync('userData').lmpt_userid
	
  }
  return config
})

export default Request

src下创建app文件,并完善工程文件

//在app文件下创建api文件夹 如:app/api/index.ts
import request from '@/utils/request' //导入request
/**
 * API 数据总操作类
 * Author Chenxiao
 * Time 2023-02-09
 * 任何傻子都能写出电脑能识别的代码,但我能写出任何人都能看懂的代码
 */

const options = {
  header: { 'content-type': 'application/x-www-form-urlencoded'},
  token: uni.getStorageSync('userData').token
}
/**
 * @method 不同请求通用写法接口
 */
export function testGet(data :any) {
  return request.get('', data)
}

export function testPost(data :any) {
  return request.post('', data, options)
}

export function testPut(data :any) {
  return request.post('', data)
}

export function testDelete(data :any) {
  return request.delete('', data)
}

/**
 * @method 正式接口
 * 
 */

}

export default API

下一节我们继续把剩余的几个配置做一个完善,例如,底部菜单数据载入,全局静态参数配置,文件自动混入等

欢迎大家收藏点赞转发,我们一起学习成长!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/40493.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信