123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- import {
- isRef,
- toRaw,
- UnwrapRef,
- computed,
- ref,
- Ref,
- WritableComputedRef,
- ComputedRef,
- shallowReactive,
- reactive,
- watchEffect,
- nextTick,
- watch,
- readonly
- } from 'vue'
- import { round, toRawType } from './index'
- import { local } from './store'
- // 复制vue源数据 防止引用修改
- export const blocking = <T>(data: T): UnwrapRef<T> => {
- const raw = toRaw(isRef(data) ? data.value : data) as any
- return raw
- // const rawType = toRawType(raw)
- // switch(rawType) {
- // case 'Array':
- // return recursionCopy(raw, raw)
- // case 'Object':
- // return recursionCopy(raw, raw)
- // default:
- // return data as UnwrapRef<T>
- // }
- }
- // 执行函数时保证参数没有其他地方引用
- export const callFunArgsBlocking = <T extends (...args: Array<any>) => any>(
- fun: T
- ): T =>
- ((...args) => {
- let result
- try {
- result = fun.apply(this, blocking(args))
- } catch (e) {
- console.error(e)
- }
- return result
- }) as T
- // 对象所有函数隔离传入参数
- const blockfcMap = new WeakMap()
- export const blockingFunCall = <T extends object>(data: T): T =>
- new Proxy(data, {
- get(...args) {
- let value = Reflect.get(...args) as any
- if (blockfcMap.has(value)) {
- return blockfcMap.get(value)
- }
- const valueType = toRawType(value)
- if (valueType === 'Object' || valueType === 'Array') {
- const blockfc = blockingFunCall(value)
- blockfcMap.set(value, blockfc)
- value = blockfc
- } else if (valueType === 'Function') {
- value = callFunArgsBlocking(value)
- }
- return value
- }
- })
- export type Tree = { children?: Array<any> }
- export const getFlatTree = <T extends Tree>(
- tree: T,
- itself: boolean = true
- ): Array<T> => {
- const options = [] as Array<T>
- if (itself) {
- options.push(tree)
- }
- if (tree.children && tree.children.length > 0) {
- for (const item of tree.children) {
- options.push(...(getFlatTree(item, itself) as Array<T>))
- }
- } else if (!itself) {
- options.push(tree)
- }
- return options
- }
- export type LinkageTree<T> = {
- select: WritableComputedRef<boolean>
- selects: Ref<Array<T>>
- children: Array<LinkageTree<T>>
- options: Array<T>
- current: T
- }
- // 生成树联动
- export const linkageSelectTree = <T extends Tree>(
- tree: T,
- itself: boolean = true,
- defSelect?: boolean,
- selects = ref([]) as Ref<Array<T>>
- ): LinkageTree<T> => {
- const alloptions = getFlatTree(tree, itself)
- const childrenCheck = tree.children
- ? tree.children.map(item => linkageSelectTree(item, itself, false, selects))
- : []
- const changeCheck = (check: boolean) => {
- alloptions.forEach(item => {
- let index = selects.value.indexOf(item)
- if (!~index) {
- index = selects.value.indexOf(reactive(item as any))
- }
- if (~index && !check) {
- selects.value.splice(index, 1)
- // selects.value = [...selects.value]
- } else if (!~index && check) {
- selects.value.push(item)
- // selects.value = [...selects.value]
- }
- })
- }
- let cache: boolean
- const allCheck = computed({
- get: () => {
- let current = true
- for (const option of alloptions) {
- let i = 0
- for (; i < selects.value.length; i++) {
- const select = toRaw(selects.value[i])
- if (toRaw(option) === select) {
- break
- }
- }
- if (i === selects.value.length) {
- current = false
- break
- }
- }
- cache = current
- return current
- },
- set: check => {
- changeCheck(check)
- }
- })
- if (defSelect) {
- nextTick(() => (allCheck.value = defSelect))
- }
- return {
- current: tree,
- select: allCheck,
- children: childrenCheck,
- selects,
- options: alloptions
- }
- }
- export type SimleTree<T> = Omit<
- LinkageTree<T>,
- 'select' | 'selects' | 'children'
- > & { children: Array<SimleTree<T>> }
- //获取选择树路径
- export const getLinkageTreeLocal = <T extends object>(
- tree: SimleTree<T>,
- select: T
- ) => {
- if (toRaw(tree) === toRaw(select)) {
- return [select]
- } else if (tree.children) {
- for (const item of tree.children) {
- const locals = getLinkageTreeLocal(item, select)
- if (locals.length) {
- return [tree, ...locals]
- }
- }
- }
- return []
- }
- export const getLinkageOptionLocal = <T extends object>(
- tree: SimleTree<T>,
- option: T
- ): Array<T> => {
- if (tree.options.includes(option)) {
- for (const item of tree.children) {
- const locals = getLinkageOptionLocal(item, option)
- if (locals.length) {
- return [tree.current, ...locals]
- }
- }
- return [tree.current]
- }
- return []
- }
- export type Stack<T> = {
- push: (raw: T) => void
- pop: () => T
- length: ComputedRef<number>
- current: ComputedRef<T>
- }
- // 栈构建
- export const stackFactory = <T>(initVal?: T, debug?: boolean): Stack<T> => {
- const stack = shallowReactive([]) as Array<T>
- if (initVal !== void 0) {
- stack.push(initVal)
- }
- return {
- push(raw: T) {
- stack.push(raw)
- },
- pop() {
- let ret = stack[stack.length-- - 1]
- return ret
- },
- current: computed(() => {
- return stack[stack.length - 1]
- }),
- length: computed(() => stack.length)
- }
- }
- export const fastStacksValue = <T extends { [key in any]: Stack<any> }>(
- stacks: T
- ) => {
- const result = {} as {
- [key in keyof T]: UnwrapRef<T[key]['current']['value']>
- }
- const keys = Object.keys(stacks) as Array<keyof T>
- const proxy = new Proxy(result, {
- get(_, key: keyof T) {
- if (keys.includes(key)) {
- return isRef(stacks[key].current.value)
- ? (stacks[key].current.value as any).value
- : stacks[key].current.value
- } else {
- return stacks[key]
- }
- },
- set(_, key: keyof T, val) {
- if (isRef(stacks[key].current.value)) {
- ;(stacks[key].current.value as any).value = val
- return true
- } else {
- return false
- }
- }
- })
- return proxy
- }
- export type MarkStack<T, K> = {
- push(raw: K, key: T): ReturnType<Stack<K>['push']>
- pop(key: T): ReturnType<Stack<K>['pop']>
- get(key: T): Stack<K>['current']
- }
- // 标识栈构建
- export const markStackFactory = <T extends object, K>() => {
- const markMap = shallowReactive(new Map<T, Stack<K>>())
- return {
- push(raw: K, key: T) {
- if (!markMap.has(key)) {
- markMap.set(key, stackFactory<K>())
- }
- const stack = markMap.get(key)
- stack.push(raw)
- },
- pop(key: T) {
- const stack = markMap.get(key)
- if (stack) {
- const ret = stack.pop()
- if (!stack.length.value) {
- markMap.delete(key)
- }
- return ret
- }
- },
- get(key: T) {
- const stack = markMap.get(key)
- if (stack) {
- return stack.current
- }
- }
- }
- }
- export type ManageStack<T, K> = {
- push(raw: K, key?: T): ReturnType<Stack<K>['push']>
- pop(key?: T): ReturnType<Stack<K>['pop']>
- get(key?: T): Stack<K>['current']
- }
- export const mangeStackFactory = <T extends object, K>() => {
- const stack = stackFactory<K>()
- const markStack = markStackFactory<T, K>()
- return {
- push: (raw: K, key?: T) =>
- key ? markStack.push(raw, key) : stack.push(raw),
- pop: (key: T) => {
- return key ? markStack.pop(key) : stack.pop()
- },
- get: (key: T) => {
- return key && markStack.get(key) ? markStack.get(key) : stack.current
- }
- }
- }
- export const watchGroupChange = <T>(
- origin: Ref<Array<T>> | Array<T>,
- addCallback: (atom: T) => void,
- removeCallback?: (atom: T) => void
- ) => {
- watch(
- origin,
- (ctrls: Array<T>, oldCtrls: Array<T>) => {
- if (oldCtrls && removeCallback) {
- oldCtrls.filter(item => !ctrls.includes(item)).forEach(removeCallback)
- }
- ;(oldCtrls
- ? ctrls.filter(item => !oldCtrls.includes(item))
- : ctrls
- ).forEach(addCallback)
- },
- { immediate: true }
- )
- }
- export const genCountDown = (
- localKey: string,
- mis: number,
- preTime?: number
- ) => {
- if (!preTime) {
- preTime = Number(local.get(localKey)) || 0
- }
- const countmis = ref(0)
- let time
- const update = () => {
- const now = Date.now()
- const downmis = round((now - preTime) / 1000, 0)
- if (downmis < mis) {
- countmis.value = mis - downmis
- time = setTimeout(update, 1000)
- } else {
- countmis.value = 0
- local.del(localKey)
- }
- }
- local.set(localKey, preTime.toString())
- update()
- return {
- count: countmis,
- update: (time: number) => {
- clearTimeout(time)
- preTime = time
- local.set(localKey, preTime.toString())
- update()
- }
- }
- }
- function isTabletf() {
- // 获取设备的屏幕宽度和高度
- var screenWidth = window.screen.width;
- var screenHeight = window.screen.height;
- // 计算屏幕的对角线长度
- var diagonalSize = Math.sqrt(Math.pow(screenWidth, 2) + Math.pow(screenHeight, 2));
- // 判断屏幕的对角线长度是否大于等于7英寸(一般认为大于等于7英寸的设备是平板)
- if (diagonalSize >= 7) {
- return true;
- } else {
- return false;
- }
- }
- function isPCf() {
- const ua = navigator.userAgent.toLowerCase();
- const agents = ["android", "iphone", "symbianos", "windows phone", "ipad", "ipod"];
- for (let i = 0; i < agents.length; i++) {
- if (ua.indexOf(agents[i]) !== -1) {
- console.error(agents[i])
- return false;
- }
- }
- return true;
- }
- export const os = (function () {
- let ua = navigator.userAgent.toLowerCase();
- let isWindowsPhone = /(?:windows phone)/.test(ua)
- let isSymbian = /(?:symbianOS)/.test(ua) || isWindowsPhone
- let isAndroid = /(?:android)/.test(ua)
- let isFireFox = /(?:firefox)/.test(ua)
- let isChrome = /(?:chrome|crios)/.test(ua)
- let isTablet = isTabletf()
- let isPhone = /(?:iphone)/.test(ua) && !isTablet
- // let isPc = !isPhone && !isAndroid && !isSymbian && !isTablet
- let isPc = isPCf()
- let isWX = /(?:microMessenger)/.test(ua)
- // if (isPc && navigator.maxTouchPoints > 1) {
- // isTablet = true
- // }
- const isHorizontal = ref(false)
- const getHorizotal = () =>
- window.innerWidth > window.innerHeight && window.innerWidth - 80 > 320
- let timeout
- if (!isPc) {
- const changHorizontal = () => {
- isHorizontal.value = getHorizotal()
- clearTimeout(timeout)
- timeout = setTimeout(() => {
- isHorizontal.value = getHorizotal()
- }, 300)
- }
- window.addEventListener('resize', changHorizontal)
- changHorizontal()
- }
- return {
- isTablet: isTablet,
- isPhone: isPhone,
- isAndroid: isAndroid,
- isPc: isPc,
- isWX: isWX,
- isHorizontal
- }
- })()
|