├── CHANGELOG.md
├── .npmignore
├── .gitignore
├── uni_modules
├── tob-use
│ ├── watch
│ │ ├── watchWithFilter
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── watchOnce
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── whenever
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── debouncedWatch
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── throttledWatch
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── pausableWatch
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── watchAtMost
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── ignorableWatch
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ └── until
│ │ │ └── index.js
│ ├── utilities
│ │ ├── createReactiveFn
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── throttledRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── debouncedRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── isDefined
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── not
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── or
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── and
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── get
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── reactivePick
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── createUnrefFn
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── eagerComputed
│ │ │ └── index.js
│ │ ├── refDefault
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── reactify
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── set
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useDebounceFn
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useLastChanged
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useThrottleFn
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── toReactive
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useClamp
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── autoResetRef
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── biSyncRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── syncRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── createEventHook
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useDebounce
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── makeDestructurable
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useCounter
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useThrottle
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── toRefs
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useToggle
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useEventBus
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── controlledComputed
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── extendRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── reactifyObject
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useCycleList
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useConfirmDialog
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useMemoize
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useAsyncQueue
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useOffsetPagination
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── controlledRef
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ └── asyncComputed
│ │ │ └── index.js
│ ├── component
│ │ ├── tryOnUnmounted
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── tryOnBeforeUnmount
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useMounted
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── tryOnScopeDispose
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useVModels
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── tryOnMounted
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useTemplateRefsList
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── computedInject
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ └── useVModel
│ │ │ ├── index.js
│ │ │ └── README.md
│ ├── state
│ │ └── useStorage
│ │ │ ├── README.md
│ │ │ ├── guess.js
│ │ │ └── index.js
│ ├── vite.config.js
│ ├── changelog.md
│ ├── shared
│ │ ├── create.js
│ │ ├── base.js
│ │ └── is.js
│ ├── animation
│ │ ├── useTimeoutFn
│ │ │ ├── README.md
│ │ │ └── index.js
│ │ ├── useTimeout
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ ├── useInterval
│ │ │ ├── index.js
│ │ │ └── README.md
│ │ └── useIntervalFn
│ │ │ ├── README.md
│ │ │ └── index.js
│ ├── readme.md
│ ├── package.json
│ └── media
│ │ ├── createAudio
│ │ └── README.md
│ │ └── useAudio
│ │ ├── index.js
│ │ └── README.md
└── tob-less
│ ├── changelog.md
│ ├── readme.md
│ ├── index.js
│ └── package.json
├── tea.yaml
├── docs
├── .vuepress
│ ├── public
│ │ └── images
│ │ │ ├── install.png
│ │ │ └── back-to-top.svg
│ ├── clientAppEnhance.ts
│ ├── types
│ │ ├── env.d.ts
│ │ └── components.d.ts
│ ├── components
│ │ ├── useInterval.vue
│ │ ├── eagerComputed.vue
│ │ ├── eagerComputed2.vue
│ │ ├── useInterval2.vue
│ │ └── eagerComputed3.vue
│ └── theme
│ │ ├── shared.ts
│ │ ├── layouts
│ │ └── 404.vue
│ │ └── index.ts
├── api
│ ├── utilities
│ │ ├── not.md
│ │ ├── or.md
│ │ ├── debouncedRef.md
│ │ ├── createReactiveFn.md
│ │ ├── throttledRef.md
│ │ ├── isDefined.md
│ │ ├── reactivePick.md
│ │ ├── refDefault.md
│ │ ├── createUnrefFn.md
│ │ ├── toReactive.md
│ │ ├── get.md
│ │ ├── autoResetRef.md
│ │ ├── set.md
│ │ ├── useClamp.md
│ │ ├── biSyncRef.md
│ │ ├── makeDestructurable.md
│ │ ├── and.md
│ │ ├── toRefs.md
│ │ ├── useEventBus.md
│ │ ├── useToggle.md
│ │ ├── controlledComputed.md
│ │ ├── extendRef.md
│ │ ├── useDebounceFn.md
│ │ ├── useDebounce.md
│ │ ├── useThrottle.md
│ │ ├── useCycleList.md
│ │ ├── useThrottleFn.md
│ │ ├── useLastChanged.md
│ │ ├── reactifyObject.md
│ │ ├── useCounter.md
│ │ ├── reactify.md
│ │ ├── useAsyncQueue.md
│ │ ├── useOffsetPagination.md
│ │ ├── syncRef.md
│ │ ├── createEventHook.md
│ │ ├── useConfirmDialog.md
│ │ ├── useMemoize.md
│ │ └── controlledRef.md
│ ├── component
│ │ ├── useMounted.md
│ │ ├── useTemplateRefsList.md
│ │ ├── tryOnUnmounted.md
│ │ ├── tryOnBeforeUnmount.md
│ │ ├── tryOnMounted.md
│ │ ├── tryOnScopeDispose.md
│ │ ├── useVModels.md
│ │ ├── computedInject.md
│ │ └── useVModel.md
│ ├── state
│ │ └── useStorage.md
│ ├── animation
│ │ ├── useTimeoutFn.md
│ │ ├── useTimeout.md
│ │ ├── useIntervalFn.md
│ │ └── useInterval.md
│ ├── watch
│ │ ├── watchOnce.md
│ │ ├── whenever.md
│ │ ├── watchAtMost.md
│ │ ├── watchWithFilter.md
│ │ ├── throttledWatch.md
│ │ ├── debouncedWatch.md
│ │ ├── pausableWatch.md
│ │ └── ignorableWatch.md
│ └── media
│ │ ├── createAudio.md
│ │ └── useAudio.md
├── index.md
├── guide
│ ├── start.md
│ └── index.md
└── about
│ └── index.md
├── scripts
├── templates
│ ├── api.js
│ ├── api.md
│ └── page.vue
├── shared
│ ├── modules.js
│ ├── utils.js
│ ├── log.js
│ └── paths.js
└── remove.js
├── pages.json
├── App.vue
├── main.js
├── pages
└── index
│ └── index.vue
├── index.html
├── .hbuilderx
└── launch.json
├── LICENSE
├── README.md
├── package.json
└── uni.scss
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | dist
2 | unpackage
3 | .hbuilderx
4 | node_modules
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | .cache
3 | .temp
4 | unpackage
5 | node_modules
6 | .idea
7 |
8 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchWithFilter/index.js:
--------------------------------------------------------------------------------
1 | export { watchWithFilter } from '../../shared/filters'
2 |
--------------------------------------------------------------------------------
/tea.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 1.0.0
3 | codeOwners:
4 | - "0x1D22736578C632DB6275d6478f251e5871a669D1"
5 | quorum: 1
6 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createReactiveFn/index.js:
--------------------------------------------------------------------------------
1 | export { reactify as createReactiveFn } from '../reactify'
2 |
--------------------------------------------------------------------------------
/docs/.vuepress/public/images/install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dishait/tob-use/HEAD/docs/.vuepress/public/images/install.png
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/throttledRef/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 节流的 ref,useThrottle 的别名
3 | */
4 | export { useThrottle as throttledRef } from '../useThrottle'
5 |
--------------------------------------------------------------------------------
/scripts/templates/api.js:
--------------------------------------------------------------------------------
1 | import { ref, computed, watch } from 'vue'
2 |
3 | /**
4 | * {{desc}}
5 | */
6 | export const {{name}} = () => {
7 | return
8 | }
9 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/debouncedRef/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 防抖的 ref, useDebounce 的别名
3 | */
4 | export { useDebounce as debouncedRef } from '../useDebounce'
5 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/isDefined/index.js:
--------------------------------------------------------------------------------
1 | import { unref } from 'vue'
2 |
3 | /**
4 | * 是否定义判断
5 | */
6 | export const isDefined = v => unref(v) != null
7 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/not/index.js:
--------------------------------------------------------------------------------
1 | import { computed, unref } from 'vue'
2 |
3 | /**
4 | * 取非
5 | */
6 | export const not = v => computed(() => !unref(v))
7 |
--------------------------------------------------------------------------------
/uni_modules/tob-less/changelog.md:
--------------------------------------------------------------------------------
1 | ## 1.0.1(2021-12-29)
2 | 无
3 | # changelog
4 |
5 | ## 1.0.0(2021-12-29)
6 | 1. 新特性
7 | - 原子的
8 | - mixins
9 | - 动态主题
10 | - 自定义主题
11 |
--------------------------------------------------------------------------------
/scripts/shared/modules.js:
--------------------------------------------------------------------------------
1 | const modules = {
2 | api: 'api',
3 | page: '页面'
4 | }
5 |
6 | const getModulesName = t => modules[t]
7 |
8 | module.exports = {
9 | getModulesName
10 | }
11 |
--------------------------------------------------------------------------------
/pages.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | {
4 | "path": "pages/index/index"
5 | }
6 | ],
7 | "globalStyle": {
8 | "navigationStyle": "custom",
9 | "navigationBarTextStyle": "black"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/scripts/templates/api.md:
--------------------------------------------------------------------------------
1 | # {{name}}
2 |
3 | {{desc}}
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { {{name}} } from '@/uni_modules/tob-use'
10 |
11 |
12 | ```
13 |
14 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/or/index.js:
--------------------------------------------------------------------------------
1 | import { unref, computed } from 'vue'
2 |
3 | /**
4 | * 或运算
5 | */
6 | export const or = (...args) => {
7 | return computed(() => args.some(v => unref(v)))
8 | }
9 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/and/index.js:
--------------------------------------------------------------------------------
1 | import { unref, computed } from 'vue'
2 |
3 | /**
4 | * AND 判断
5 | */
6 | export const and = (...args) => {
7 | return computed(() => args.every(v => unref(v)))
8 | }
9 |
--------------------------------------------------------------------------------
/docs/.vuepress/clientAppEnhance.ts:
--------------------------------------------------------------------------------
1 | import { defineClientAppEnhance } from '@vuepress/client'
2 |
3 | // 你自定义的 css
4 | import './index.scss'
5 |
6 | const noop = () => {}
7 |
8 | export default defineClientAppEnhance(noop)
9 |
--------------------------------------------------------------------------------
/scripts/templates/page.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | {{ name }}
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/.vuepress/types/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.vue' {
4 | import type { DefineComponent } from 'vue'
5 | const component: DefineComponent<{}, {}, any>
6 | export default component
7 | }
8 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/get/index.js:
--------------------------------------------------------------------------------
1 | import { unref } from 'vue'
2 |
3 | /**
4 | * 获取
5 | */
6 | export const get = (obj, key) => {
7 | if (key == null) {
8 | return unref(obj)
9 | }
10 | return unref(obj)[key]
11 | }
12 |
--------------------------------------------------------------------------------
/docs/api/utilities/not.md:
--------------------------------------------------------------------------------
1 | # not
2 |
3 | 取非
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { not } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(true)
12 |
13 | console.log(not(a)) // false
14 | ```
15 |
16 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnUnmounted/index.js:
--------------------------------------------------------------------------------
1 | import { getCurrentInstance, onUnmounted } from 'vue'
2 |
3 | /**
4 | * 卸载时触发
5 | */
6 | export const tryOnUnmounted = fn => {
7 | if (getCurrentInstance()) {
8 | onUnmounted(fn)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/not/README.md:
--------------------------------------------------------------------------------
1 | # not
2 |
3 | 取非
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { not } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(true)
12 |
13 | console.log(not(a)) // false
14 | ```
15 |
16 |
--------------------------------------------------------------------------------
/docs/api/utilities/or.md:
--------------------------------------------------------------------------------
1 | # or
2 |
3 | 或运算
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { or } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(true)
12 | const b = ref(false)
13 |
14 | console.log(or(a, b)) // true
15 | ```
16 |
17 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnBeforeUnmount/index.js:
--------------------------------------------------------------------------------
1 | import { getCurrentInstance, onBeforeUnmount } from 'vue'
2 |
3 | /**
4 | * 在卸载前触发
5 | */
6 | export const tryOnBeforeUnmount = fn => {
7 | if (getCurrentInstance()) {
8 | onBeforeUnmount(fn)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactivePick/index.js:
--------------------------------------------------------------------------------
1 | import { toRef, reactive } from 'vue'
2 |
3 | /**
4 | * 响应式的pick
5 | */
6 | export const reactivePick = (obj, ...keys) => {
7 | return reactive(
8 | Object.fromEntries(keys.map(k => [k, toRef(obj, k)]))
9 | )
10 | }
11 |
--------------------------------------------------------------------------------
/docs/api/utilities/debouncedRef.md:
--------------------------------------------------------------------------------
1 | # debouncedRef
2 |
3 | 防抖的 ref
4 |
5 | ## Usage
6 |
7 | [useDebounce](/api/utilities/useDebounce) 的别名,具体用法可见 👉 [useDebounce](/api/utilities/useDebounce)。
8 |
9 | ```js
10 | import { debouncedRef } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/or/README.md:
--------------------------------------------------------------------------------
1 | # or
2 |
3 | 或运算
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { or } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(true)
12 | const b = ref(false)
13 |
14 | console.log(or(a, b)) // true
15 | ```
16 |
17 |
--------------------------------------------------------------------------------
/docs/api/utilities/createReactiveFn.md:
--------------------------------------------------------------------------------
1 | # createReactiveFn
2 |
3 | 将普通函数转换为响应式函数
4 |
5 | ## Usage
6 |
7 | [reactify](/api/utilities/reactify) 的别名,具体用法可见 👉 [reactify](/api/utilities/reactify)。
8 |
9 | ```ts
10 | import { createReactiveFn } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/docs/api/utilities/throttledRef.md:
--------------------------------------------------------------------------------
1 | # throttledRef
2 |
3 | 节流的 ref
4 |
5 | ## Usage
6 |
7 | [useThrottle](/api/utilities/useThrottle) 的别名,具体用法可见 👉 [useThrottle](/api/utilities/useThrottle)。
8 |
9 | ```js
10 | import { throttledRef } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
14 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useMounted/index.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | /**
4 | * 使用被挂载状态
5 | */
6 | export const useMounted = () => {
7 | const isMounted = ref(false)
8 |
9 | onMounted(() => {
10 | isMounted.value = true
11 | })
12 |
13 | return isMounted
14 | }
15 |
--------------------------------------------------------------------------------
/docs/.vuepress/types/components.d.ts:
--------------------------------------------------------------------------------
1 | // generated by unplugin-vue-components
2 | // We suggest you to commit this file into source control
3 | // Read more: https://github.com/vuejs/vue-next/pull/3399
4 |
5 | declare module 'vue' {
6 | export interface GlobalComponents {}
7 | }
8 |
9 | export {}
10 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/debouncedRef/README.md:
--------------------------------------------------------------------------------
1 | # debouncedRef
2 |
3 | 防抖的 ref
4 |
5 | ## Usage
6 |
7 | [useDebounce](/api/utilities/useDebounce) 的别名,具体用法可见 👉 [useDebounce](/api/utilities/useDebounce)。
8 |
9 | ```js
10 | import { debouncedRef } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createReactiveFn/README.md:
--------------------------------------------------------------------------------
1 | # createReactiveFn
2 |
3 | 将普通函数转换为响应式函数
4 |
5 | ## Usage
6 |
7 | [reactify](/api/utilities/reactify) 的别名,具体用法可见 👉 [reactify](/api/utilities/reactify)。
8 |
9 | ```ts
10 | import { createReactiveFn } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/throttledRef/README.md:
--------------------------------------------------------------------------------
1 | # throttledRef
2 |
3 | 节流的 ref
4 |
5 | ## Usage
6 |
7 | [useThrottle](/api/utilities/useThrottle) 的别名,具体用法可见 👉 [useThrottle](/api/utilities/useThrottle)。
8 |
9 | ```js
10 | import { throttledRef } from '@/uni_modules/tob-use'
11 | ```
12 |
13 |
14 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createUnrefFn/index.js:
--------------------------------------------------------------------------------
1 | import { unref } from 'vue'
2 |
3 | /**
4 | * 创建解 ref 函数
5 | */
6 | export const createUnrefFn = fn => {
7 | return function (...args) {
8 | return fn.apply(
9 | this,
10 | // 解除所有 ref 的参数
11 | args.map(v => unref(v))
12 | )
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/scripts/shared/utils.js:
--------------------------------------------------------------------------------
1 | // 空函数
2 | const noop = () => {}
3 |
4 | // 创建一个防抖函数
5 | const useDebounce = (fn = noop, delay = 1000) => {
6 | let timeout = null
7 | return () => {
8 | clearTimeout(timeout)
9 | timeout = setTimeout(fn, delay)
10 | }
11 | }
12 |
13 | module.exports = {
14 | useDebounce
15 | }
16 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnScopeDispose/index.js:
--------------------------------------------------------------------------------
1 | import { getCurrentScope, onScopeDispose } from 'vue'
2 |
3 | /**
4 | * 在副作用作用域被 stop 时,触发回调
5 | */
6 | export const tryOnScopeDispose = fn => {
7 | if (getCurrentScope()) {
8 | onScopeDispose(fn)
9 | return true
10 | }
11 | return false
12 | }
13 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useVModels/index.js:
--------------------------------------------------------------------------------
1 | import { useVModel } from '../useVModel'
2 |
3 | /**
4 | * 使用多个的 v-model
5 | */
6 | export const useVModels = (props, emit, options = {}) => {
7 | const ret = {}
8 | for (const key in props) {
9 | ret[key] = useVModel(props, key, emit, options)
10 | }
11 | return ret
12 | }
13 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/eagerComputed/index.js:
--------------------------------------------------------------------------------
1 | import { shallowRef, watchSyncEffect, readonly } from 'vue'
2 |
3 | /**
4 | * 及时的计算属性
5 | */
6 | export const eagerComputed = fn => {
7 | const result = shallowRef()
8 |
9 | watchSyncEffect(() => {
10 | result.value = fn()
11 | })
12 |
13 | return readonly(result)
14 | }
15 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/refDefault/index.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 |
3 | /**
4 | * ref 的默认值
5 | */
6 | export const refDefault = (source, defaultValue) => {
7 | return computed({
8 | get() {
9 | return source.value ?? defaultValue
10 | },
11 | set(value) {
12 | source.value = value
13 | }
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/App.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactify/index.js:
--------------------------------------------------------------------------------
1 | import { computed, unref } from 'vue'
2 |
3 | /**
4 | * 将普通函数转换为响应式函数
5 | */
6 | export const reactify = fn => {
7 | return function (...args) {
8 | return computed(() =>
9 | fn.apply(
10 | this,
11 | // 解除所有 ref 的参数
12 | args.map(v => unref(v))
13 | )
14 | )
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/set/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 设置
3 | */
4 | export const set = (...args) => {
5 | // 双参数时,直接赋值
6 | if (args.length === 2) {
7 | const [ref, value] = args
8 | ref.value = value
9 | }
10 |
11 | // 三参数时,赋值到某个键
12 | if (args.length === 3) {
13 | const [target, key, value] = args
14 | target[key] = value
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchOnce/index.js:
--------------------------------------------------------------------------------
1 | import { nextTick, watch } from 'vue'
2 |
3 | /**
4 | * 一次性监听
5 | */
6 | export const watchOnce = (source, cb, options = {}) => {
7 | const stop = watch(
8 | source,
9 | (...args) => {
10 | // 触发后直接 stop 掉监听
11 | nextTick(stop)
12 | return cb(...args)
13 | },
14 | options
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/whenever/index.js:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 |
3 | /**
4 | * 仅当为真时触发
5 | */
6 | export const whenever = (source, cb, options) => {
7 | return watch(
8 | source,
9 | (v, ov, onInvalidate) => {
10 | // 仅当为 truthy 时触发回调
11 | if (v) {
12 | cb(v, ov, onInvalidate)
13 | }
14 | },
15 | options
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/docs/api/utilities/isDefined.md:
--------------------------------------------------------------------------------
1 | # isDefined
2 |
3 | 是否定义判断
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { isDefined } from '@/uni_modules/tob-use'
10 |
11 | const example = ref(undefined)
12 |
13 | if (isDefined(example)) {
14 | console.log("定义了")
15 | } else {
16 | console.log("未定义") // 将输出 '未定义'
17 | }
18 | ```
19 |
20 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useDebounceFn/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | debounceFilter,
3 | createFilterWrapper
4 | } from '../../shared/filters'
5 |
6 | /**
7 | * 使用防抖函数
8 | */
9 | export const useDebounceFn = (
10 | fn,
11 | ms = 200,
12 | options = {}
13 | ) => {
14 | return createFilterWrapper(
15 | debounceFilter(ms, options),
16 | fn
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnMounted/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | getCurrentInstance,
3 | nextTick,
4 | onMounted
5 | } from 'vue'
6 |
7 | /**
8 | * 在挂载后触发
9 | */
10 | export const tryOnMounted = (fn, sync = true) => {
11 | if (getCurrentInstance()) {
12 | onMounted(fn)
13 | } else if (sync) {
14 | fn()
15 | } else {
16 | nextTick(fn)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/isDefined/README.md:
--------------------------------------------------------------------------------
1 | # isDefined
2 |
3 | 是否定义判断
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { isDefined } from '@/uni_modules/tob-use'
10 |
11 | const example = ref(undefined)
12 |
13 | if (isDefined(example)) {
14 | console.log("定义了")
15 | } else {
16 | console.log("未定义") // 将输出 '未定义'
17 | }
18 | ```
19 |
20 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useLastChanged/index.js:
--------------------------------------------------------------------------------
1 | import { ref, watch } from 'vue'
2 | import { timestamp } from '../../shared/base'
3 |
4 | /**
5 | * 获取最后一次更新
6 | */
7 | export const useLastChanged = (source, options = {}) => {
8 | const ms = ref(options.initialValue ?? null)
9 |
10 | watch(source, () => (ms.value = timestamp()), options)
11 |
12 | return ms
13 | }
14 |
--------------------------------------------------------------------------------
/docs/api/component/useMounted.md:
--------------------------------------------------------------------------------
1 | # useMounted
2 |
3 | 使用被挂载状态
4 |
5 | ## Usage
6 |
7 | ```html
8 |
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/docs/api/utilities/reactivePick.md:
--------------------------------------------------------------------------------
1 | # reactivePick
2 |
3 | 响应式的 pick
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { reactivePick } from '@/uni_modules/tob-use'
10 |
11 | const obj = reactive({
12 | x: 0,
13 | y: 0,
14 | elementX: 0,
15 | elementY: 0,
16 | })
17 |
18 | const picked = reactivePick(obj, 'x', 'elementX') // { x: 0, elementX: 0 }
19 | ```
20 |
21 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useThrottleFn/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | throttleFilter,
3 | createFilterWrapper
4 | } from '../../shared/filters'
5 |
6 | /**
7 | * 使用节流函数
8 | */
9 | export const useThrottleFn = (
10 | fn,
11 | ms = 200,
12 | trailing = true,
13 | leading = true
14 | ) => {
15 | return createFilterWrapper(
16 | throttleFilter(ms, trailing, leading),
17 | fn
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/docs/api/state/useStorage.md:
--------------------------------------------------------------------------------
1 | # useStorage
2 |
3 | 使用存储
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useStorage } from '@/uni_modules/tob-use'
12 |
13 | const state = useStorage('vue-use-local-storage', {
14 | name: 'Banana',
15 | color: 'Yellow',
16 | size: 'Medium',
17 | })
18 |
19 | // delete data from storage
20 | state.value = null
21 | ```
22 |
--------------------------------------------------------------------------------
/scripts/shared/log.js:
--------------------------------------------------------------------------------
1 | const { terminalColor } = require('@markthree/node-shared')
2 |
3 | const noticeSuccess = (type = '创建') => {
4 | const msg = terminalColor.green(type + '成功')
5 | console.log(msg)
6 | }
7 |
8 | const noticeFail = (type = '创建') => {
9 | const msg = terminalColor.red(type + '失败')
10 | console.log(msg)
11 | }
12 |
13 | module.exports = {
14 | noticeFail,
15 | noticeSuccess
16 | }
17 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useMounted/README.md:
--------------------------------------------------------------------------------
1 | # useMounted
2 |
3 | 使用被挂载状态
4 |
5 | ## Usage
6 |
7 | ```html
8 |
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import App from './App'
2 |
3 | // #ifndef VUE3
4 | import Vue from 'vue'
5 | Vue.config.productionTip = false
6 | App.mpType = 'app'
7 | const app = new Vue({
8 | ...App
9 | })
10 | app.$mount()
11 | // #endif
12 |
13 | // #ifdef VUE3
14 | import { createSSRApp } from 'vue'
15 | export function createApp() {
16 | const app = createSSRApp(App)
17 | return {
18 | app
19 | }
20 | }
21 | // #endif
--------------------------------------------------------------------------------
/uni_modules/tob-use/state/useStorage/README.md:
--------------------------------------------------------------------------------
1 | # useStorage
2 |
3 | 使用存储
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useStorage } from '@/uni_modules/tob-use'
12 |
13 | const state = useStorage('vue-use-local-storage', {
14 | name: 'Banana',
15 | color: 'Yellow',
16 | size: 'Medium',
17 | })
18 |
19 | // delete data from storage
20 | state.value = null
21 | ```
22 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactivePick/README.md:
--------------------------------------------------------------------------------
1 | # reactivePick
2 |
3 | 响应式的 pick
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { reactivePick } from '@/uni_modules/tob-use'
10 |
11 | const obj = reactive({
12 | x: 0,
13 | y: 0,
14 | elementX: 0,
15 | elementY: 0,
16 | })
17 |
18 | const picked = reactivePick(obj, 'x', 'elementX') // { x: 0, elementX: 0 }
19 | ```
20 |
21 |
--------------------------------------------------------------------------------
/docs/api/utilities/refDefault.md:
--------------------------------------------------------------------------------
1 | # refDefault
2 |
3 | ref 的默认值
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { refDefault } from '@/uni_modules/tob-use'
10 |
11 | // 未定义的 ref
12 | const raw = ref()
13 |
14 | // 返回一个计算属性
15 | const state = refDefault(raw, 0)
16 |
17 | state.value // 0
18 |
19 | raw.value = 1
20 | state.value // 1
21 |
22 | state.value = 2
23 | raw.value // 2
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/docs/api/utilities/createUnrefFn.md:
--------------------------------------------------------------------------------
1 | # createUnrefFn
2 |
3 | 创建解 ref 函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { createUnrefFn } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(1)
12 | const b = ref(2)
13 |
14 | const sum = (a, b) => a + b
15 |
16 | const unrefSum = createUnrefFn(sum)
17 |
18 | sum(a, b) /* ❌ 错误的 ref 参数相加 */
19 | unrefSum(a, b) /* ✔️ 将自动解 ref 后相加 */
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/useInterval.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | 每 200 毫秒更新: {{ counter }}
16 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/refDefault/README.md:
--------------------------------------------------------------------------------
1 | # refDefault
2 |
3 | ref 的默认值
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { refDefault } from '@/uni_modules/tob-use'
10 |
11 | // 未定义的 ref
12 | const raw = ref()
13 |
14 | // 返回一个计算属性
15 | const state = refDefault(raw, 0)
16 |
17 | state.value // 0
18 |
19 | raw.value = 1
20 | state.value // 1
21 |
22 | state.value = 2
23 | raw.value // 2
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/debouncedWatch/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | debounceFilter,
3 | watchWithFilter
4 | } from '../../shared/filters'
5 |
6 | /**
7 | * 防抖监听
8 | */
9 | export const debouncedWatch = (
10 | source,
11 | cb,
12 | options = {}
13 | ) => {
14 | const { debounce = 0, ...watchOptions } = options
15 |
16 | return watchWithFilter(source, cb, {
17 | ...watchOptions,
18 | eventFilter: debounceFilter(debounce)
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/docs/api/utilities/toReactive.md:
--------------------------------------------------------------------------------
1 | # toReactive
2 |
3 | 转化为 Reactive
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { toReactive } from '@/uni_modules/tob-use'
10 |
11 | const origin = ref({ foo: 'bar' })
12 |
13 | origin.value.foo // bar
14 |
15 | const state = toReactive(origin)
16 |
17 | state.foo // bar
18 |
19 | origin.value = { bar: 'foo' }
20 |
21 | state.foo // undefined
22 | state.bar // foo
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/pages/index/index.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | TODO {{counter}}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useTemplateRefsList/index.js:
--------------------------------------------------------------------------------
1 | import { onBeforeUpdate, ref } from 'vue'
2 |
3 | /**
4 | * 获取模板元素的列表
5 | */
6 | export const useTemplateRefsList = () => {
7 | const refs = ref([])
8 |
9 | // 获取 ref 元素
10 | refs.value.set = el => {
11 | if (el) {
12 | refs.value.push(el)
13 | }
14 | }
15 |
16 | // 更新前重置列表
17 | const reset = () => (refs.value.length = 0)
18 | onBeforeUpdate(reset)
19 | return refs
20 | }
21 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createUnrefFn/README.md:
--------------------------------------------------------------------------------
1 | # createUnrefFn
2 |
3 | 创建解 ref 函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { createUnrefFn } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(1)
12 | const b = ref(2)
13 |
14 | const sum = (a, b) => a + b
15 |
16 | const unrefSum = createUnrefFn(sum)
17 |
18 | sum(a, b) /* ❌ 错误的 ref 参数相加 */
19 | unrefSum(a, b) /* ✔️ 将自动解 ref 后相加 */
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/docs/api/utilities/get.md:
--------------------------------------------------------------------------------
1 | # get
2 |
3 | 获取
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { get } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(42)
12 |
13 | console.log(get(a)) // 42
14 | ```
15 |
16 | 或者获取具体对象的 `key`
17 |
18 |
19 | ```js
20 | import { ref } from 'vue'
21 | import { get } from '@/uni_modules/tob-use'
22 |
23 | const foo = ref({
24 | bar: 100
25 | })
26 |
27 | console.log(get(foo, 'bar')) // 100
28 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/autoResetRef.md:
--------------------------------------------------------------------------------
1 | # autoResetRef
2 |
3 | 自动重置 ref
4 |
5 |
6 | ## Usage
7 |
8 | ```js
9 | import { ref } from 'vue'
10 | import { autoResetRef } from '@/uni_modules/tob-use'
11 |
12 | // 返回一个 ref,第二个参数可设置延迟,默认为 10 秒
13 | const message = autoResetRef('默认', 1000)
14 |
15 | message.value = '更新了'
16 |
17 | console.log(message.value) // 输出 更新了
18 |
19 | setTimeout(() => {
20 | console.log(message.value) // 输出 默认
21 | }, 2000)
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/toReactive/README.md:
--------------------------------------------------------------------------------
1 | # toReactive
2 |
3 | 转化为 Reactive
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { toReactive } from '@/uni_modules/tob-use'
10 |
11 | const origin = ref({ foo: 'bar' })
12 |
13 | origin.value.foo // bar
14 |
15 | const state = toReactive(origin)
16 |
17 | state.foo // bar
18 |
19 | origin.value = { bar: 'foo' }
20 |
21 | state.foo // undefined
22 | state.bar // foo
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useClamp/index.js:
--------------------------------------------------------------------------------
1 | import { clamp } from '../../shared/is'
2 | import { ref, computed, unref } from 'vue'
3 |
4 | /**
5 | * 在两个值范围之间取一个值
6 | */
7 | export const useClamp = (value, min, max) => {
8 | const _value = ref(value)
9 | return computed({
10 | get() {
11 | return clamp(_value.value, unref(min), unref(max))
12 | },
13 | set(value) {
14 | _value.value = clamp(value, unref(min), unref(max))
15 | }
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/docs/.vuepress/components/eagerComputed.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 | 点击 👉
20 |
21 |
22 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/get/README.md:
--------------------------------------------------------------------------------
1 | # get
2 |
3 | 获取
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { get } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(42)
12 |
13 | console.log(get(a)) // 42
14 | ```
15 |
16 | 或者获取具体对象的 `key`
17 |
18 |
19 | ```js
20 | import { ref } from 'vue'
21 | import { get } from '@/uni_modules/tob-use'
22 |
23 | const foo = ref({
24 | bar: 100
25 | })
26 |
27 | console.log(get(foo, 'bar')) // 100
28 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/vite.config.js:
--------------------------------------------------------------------------------
1 | // 引入 vite 是为了打包后发布 npm
2 | import path from 'path'
3 | import { defineConfig } from 'vite'
4 |
5 | export default defineConfig({
6 | build: {
7 | lib: {
8 | name: 'index',
9 | fileName: format => `index.${format}.js`,
10 | entry: path.resolve(__dirname, './index.js')
11 | },
12 | rollupOptions: {
13 | external: ['vue'],
14 | output: {
15 | globals: {
16 | vue: 'Vue'
17 | }
18 | }
19 | }
20 | }
21 | })
22 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/autoResetRef/README.md:
--------------------------------------------------------------------------------
1 | # autoResetRef
2 |
3 | 自动重置 ref
4 |
5 |
6 | ## Usage
7 |
8 | ```js
9 | import { ref } from 'vue'
10 | import { autoResetRef } from '@/uni_modules/tob-use'
11 |
12 | // 返回一个 ref,第二个参数可设置延迟,默认为 10 秒
13 | const message = autoResetRef('默认', 1000)
14 |
15 | message.value = '更新了'
16 |
17 | console.log(message.value) // 输出 更新了
18 |
19 | setTimeout(() => {
20 | console.log(message.value) // 输出 默认
21 | }, 2000)
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/docs/api/component/useTemplateRefsList.md:
--------------------------------------------------------------------------------
1 | # useTemplateRefsList
2 |
3 | 获取模板元素的列表
4 |
5 | ## Usage
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 |
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/docs/api/utilities/set.md:
--------------------------------------------------------------------------------
1 | # set
2 |
3 | 设置
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { set } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(0)
12 |
13 | set(a, 1)
14 |
15 | a.value // 1
16 | ```
17 |
18 | 或者对对象具体的 `key` 设置
19 |
20 | ```js
21 | import { reactive } from 'vue'
22 | import { set } from '@/uni_modules/tob-use'
23 |
24 | const foo = reactive({
25 | bar: 0
26 | })
27 |
28 | set(foo, 'bar', 1)
29 |
30 | foo.bar // 1
31 | ```
32 |
33 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/changelog.md:
--------------------------------------------------------------------------------
1 | ## 1.1.0(2022-05-17)
2 | ## feat
3 | - useStorage
4 | ## 1.0.14(2022-03-11)
5 | - 更小的包引入
6 | ## 1.0.13(2022-03-11)
7 | - 优化音频自然播放体验
8 | ## 1.0.12(2022-03-11)
9 | - 添加音频播放导出
10 | ## 1.0.11(2022-03-11)
11 | - 添加音频播放
12 | ## 1.0.10(2022-03-02)
13 | - 更新文档
14 | ## 1.0.9(2022-03-02)
15 | - 更新文档链接
16 | ## 1.0.8(2022-03-02)
17 | - 更新文档引用
18 | ## 1.0.7(2022-03-02)
19 | - 更新文档链接
20 | ## 1.0.6(2022-03-02)
21 | - 60+ 基础 api 更新
22 | ## 0.0.1(2022-01-23)
23 | - test
24 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useTemplateRefsList/README.md:
--------------------------------------------------------------------------------
1 | # useTemplateRefsList
2 |
3 | 获取模板元素的列表
4 |
5 | ## Usage
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 |
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/set/README.md:
--------------------------------------------------------------------------------
1 | # set
2 |
3 | 设置
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { set } from '@/uni_modules/tob-use'
10 |
11 | const a = ref(0)
12 |
13 | set(a, 1)
14 |
15 | a.value // 1
16 | ```
17 |
18 | 或者对对象具体的 `key` 设置
19 |
20 | ```js
21 | import { reactive } from 'vue'
22 | import { set } from '@/uni_modules/tob-use'
23 |
24 | const foo = reactive({
25 | bar: 0
26 | })
27 |
28 | set(foo, 'bar', 1)
29 |
30 | foo.bar // 1
31 | ```
32 |
33 |
--------------------------------------------------------------------------------
/scripts/shared/paths.js:
--------------------------------------------------------------------------------
1 | const { createPath } = require('@markthree/node-shared')
2 |
3 | // 辅助路径工具
4 | const p = createPath(__dirname)
5 |
6 | // 模板路径
7 | const templatePaths = {
8 | apiJs: p('../templates/api.js'),
9 | apiMd: p('../templates/api.md'),
10 | page: p('../templates/page.vue')
11 | }
12 |
13 | // 基础目标路径
14 | const baseDestPaths = {
15 | api: p('../../uni_modules/tob-use'),
16 | page: p('../../pages')
17 | }
18 |
19 | module.exports = {
20 | p,
21 | templatePaths,
22 | baseDestPaths
23 | }
24 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/biSyncRef/index.js:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 |
3 | /**
4 | * 双向同步
5 | */
6 | export const biSyncRef = (l, r) => {
7 | const watchOptions = {
8 | flush: 'sync',
9 | immediate: true
10 | }
11 |
12 | const sync1 = newValue => (r.value = newValue)
13 | const stop1 = watch(l, sync1, watchOptions)
14 |
15 | const sync2 = newValue => (l.value = newValue)
16 | const stop2 = watch(r, sync2, watchOptions)
17 |
18 | return () => {
19 | stop1()
20 | stop2()
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/syncRef/index.js:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 |
3 | /**
4 | * 保持目标 ref 跟源同步
5 | */
6 | export const syncRef = (source, targets, options = {}) => {
7 | const {
8 | deep = false,
9 | flush = 'sync',
10 | immediate = true
11 | } = options
12 |
13 | if (!Array.isArray(targets)) {
14 | targets = [targets]
15 | }
16 |
17 | return watch(
18 | source,
19 | newValue =>
20 | targets.forEach(target => (target.value = newValue)),
21 | { flush, deep, immediate }
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/docs/api/component/tryOnUnmounted.md:
--------------------------------------------------------------------------------
1 | # tryOnUnmounted
2 |
3 | 卸载时触发
4 |
5 | 比原生的 `onUnmounted` 更安全
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { tryOnUnmounted } from '@/uni_modules/tob-use'
11 |
12 | // 不在组件内,将不会注册回调
13 | tryOnUnmounted(() => {
14 | console.log("这将不做任何事情")
15 | })
16 | ```
17 |
18 | ```html
19 |
27 | ```
28 |
29 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/throttledWatch/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | watchWithFilter,
3 | throttleFilter
4 | } from '../../shared/filters'
5 |
6 | /**
7 | * 节流型监听
8 | */
9 | export const throttledWatch = (
10 | source,
11 | cb,
12 | options = {}
13 | ) => {
14 | const {
15 | throttle = 0,
16 | trailing = true,
17 | leading = true,
18 | ...watchOptions
19 | } = options
20 |
21 | return watchWithFilter(source, cb, {
22 | ...watchOptions,
23 | eventFilter: throttleFilter(throttle, trailing, leading)
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/docs/api/utilities/useClamp.md:
--------------------------------------------------------------------------------
1 | # useClamp
2 |
3 | 在两个值范围之间取一个值
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useClamp } from '@/uni_modules/tob-use'
10 |
11 | const min = ref(0)
12 | const max = ref(10)
13 |
14 | // 限定范围 0 - 10
15 | const result = useClamp(0, min, max)
16 |
17 | result.value = 20
18 |
19 | result.value // 超出最大,仍然是 10
20 |
21 | result.value = -1
22 |
23 | result.value // 超出最小,仍然是 0
24 |
25 | max.value = 20 // 调整最大值为 20
26 |
27 | result.value = 20
28 |
29 | result.value // 20
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnUnmounted/README.md:
--------------------------------------------------------------------------------
1 | # tryOnUnmounted
2 |
3 | 卸载时触发
4 |
5 | 比原生的 `onUnmounted` 更安全
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { tryOnUnmounted } from '@/uni_modules/tob-use'
11 |
12 | // 不在组件内,将不会注册回调
13 | tryOnUnmounted(() => {
14 | console.log("这将不做任何事情")
15 | })
16 | ```
17 |
18 | ```html
19 |
27 | ```
28 |
29 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/pausableWatch/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | watchWithFilter,
3 | pausableFilter
4 | } from '../../shared/filters'
5 |
6 | /**
7 | * 可暂停的监听
8 | */
9 | export const pausableWatch = (source, cb, options = {}) => {
10 | const { eventFilter: filter, ...watchOptions } = options
11 |
12 | const { eventFilter, pause, resume, isActive } =
13 | pausableFilter(filter)
14 |
15 | const stop = watchWithFilter(source, cb, {
16 | ...watchOptions,
17 | eventFilter
18 | })
19 |
20 | return { stop, pause, resume, isActive }
21 | }
22 |
--------------------------------------------------------------------------------
/docs/api/component/tryOnBeforeUnmount.md:
--------------------------------------------------------------------------------
1 | # tryOnBeforeUnmount
2 |
3 | 在卸载前触发
4 |
5 | 比原生的 `onBeforeUnmount` 更安全
6 | ## Usage
7 |
8 | ```js
9 | import { tryOnBeforeUnmount } from '@/uni_modules/tob-use'
10 |
11 | // 不在组件内,将不会注册回调
12 | tryOnBeforeUnmount(() => {
13 | console.log("这将不做任何事情")
14 | })
15 | ```
16 |
17 | ```html
18 |
26 | ```
27 |
28 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/shared/create.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 创建一个共享的 composition-api
3 | */
4 | export const createSharedComposable = composable => {
5 | let subscribers = 0
6 | let state, scope
7 |
8 | const dispose = () => {
9 | if (scope && --subscribers <= 0) {
10 | scope.stop()
11 | state = scope = null
12 | }
13 | }
14 |
15 | return (...args) => {
16 | subscribers++
17 | if (!state) {
18 | scope = effectScope(true)
19 | state = scope.run(() => composable(...args))
20 | }
21 | onScopeDispose(dispose)
22 | return state
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/.vuepress/public/images/back-to-top.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/api/animation/useTimeoutFn.md:
--------------------------------------------------------------------------------
1 | # useTimeoutFn
2 |
3 | 定时器方法
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useTimeoutFn } from '@/uni_modules/tob-use'
11 |
12 | const {
13 | stop,
14 | start,
15 | isPending,
16 | } = useTimeoutFn(() => {
17 | // 你希望执行的函数
18 | }, 3000)
19 | ```
20 |
21 |
22 |
23 | ### 立即开始
24 |
25 | ```js
26 | import { useTimeoutFn } from '@/uni_modules/tob-use'
27 |
28 | const instance = useTimeoutFn(() => {
29 | // 你希望执行的函数
30 | }, 3000, {
31 | immediate: false // 立即开始,默认为 true
32 | })
33 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createEventHook/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 创建事件 hook
3 | */
4 | export const createEventHook = () => {
5 | const fns = []
6 |
7 | // 卸载
8 | const off = fn => {
9 | const index = fns.indexOf(fn)
10 | if (index !== -1) fns.splice(index, 1)
11 | }
12 |
13 | // 注册
14 | const on = fn => {
15 | fns.push(fn)
16 | return {
17 | off: () => off(fn)
18 | }
19 | }
20 |
21 | // 触发
22 | const trigger = param => {
23 | fns.forEach(fn => fn(param))
24 | }
25 |
26 | return {
27 | on,
28 | off,
29 | trigger
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useClamp/README.md:
--------------------------------------------------------------------------------
1 | # useClamp
2 |
3 | 在两个值范围之间取一个值
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useClamp } from '@/uni_modules/tob-use'
10 |
11 | const min = ref(0)
12 | const max = ref(10)
13 |
14 | // 限定范围 0 - 10
15 | const result = useClamp(0, min, max)
16 |
17 | result.value = 20
18 |
19 | result.value // 超出最大,仍然是 10
20 |
21 | result.value = -1
22 |
23 | result.value // 超出最小,仍然是 0
24 |
25 | max.value = 20 // 调整最大值为 20
26 |
27 | result.value = 20
28 |
29 | result.value // 20
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/docs/api/utilities/biSyncRef.md:
--------------------------------------------------------------------------------
1 | # biSyncRef
2 |
3 | 双向同步
4 |
5 | 同步两个 `ref` 参数
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { biSyncRef } from '@/uni_modules/tob-use'
12 |
13 | const a = ref('a')
14 | const b = ref('b')
15 |
16 | const stop = biSyncRef(a, b)
17 |
18 | console.log(a.value) // a
19 |
20 | b.value = 'foo'
21 |
22 | console.log(a.value) // foo
23 |
24 | a.value = 'bar'
25 |
26 | console.log(b.value) // bar
27 |
28 | stop() // 停止同步
29 |
30 | a.value = 'foo'
31 |
32 | console.log(b.value) // 仍然是 bar
33 | ```
34 |
35 |
--------------------------------------------------------------------------------
/docs/api/utilities/makeDestructurable.md:
--------------------------------------------------------------------------------
1 | # makeDestructurable
2 |
3 | 使得更好分解
4 |
5 | 即让结果可以使用对象解构或数组解构两种方式
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { makeDestructurable } from '@/uni_modules/tob-use'
12 |
13 | const bar = 1024
14 | const foo = { name: 'foo' }
15 |
16 | const obj = makeDestructurable(
17 | { foo, bar },
18 | [ foo, bar ]
19 | )
20 | ```
21 |
22 | 使用时就可以用数组解构或对象解构了 👇
23 |
24 | ```ts
25 | // 对象解构
26 | let { foo, bar } = obj
27 | ```
28 |
29 | 或者
30 |
31 | ```ts
32 | // 数组解构
33 | let [ foo, bar ] = obj
34 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnBeforeUnmount/README.md:
--------------------------------------------------------------------------------
1 | # tryOnBeforeUnmount
2 |
3 | 在卸载前触发
4 |
5 | 比原生的 `onBeforeUnmount` 更安全
6 | ## Usage
7 |
8 | ```js
9 | import { tryOnBeforeUnmount } from '@/uni_modules/tob-use'
10 |
11 | // 不在组件内,将不会注册回调
12 | tryOnBeforeUnmount(() => {
13 | console.log("这将不做任何事情")
14 | })
15 | ```
16 |
17 | ```html
18 |
26 | ```
27 |
28 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useDebounce/index.js:
--------------------------------------------------------------------------------
1 | import { ref, watch } from 'vue'
2 | import { useDebounceFn } from '../useDebounceFn'
3 |
4 | /**
5 | * 使用防抖 ref
6 | */
7 | export const useDebounce = (
8 | value,
9 | ms = 200,
10 | options = {}
11 | ) => {
12 | if (ms <= 0) {
13 | return value
14 | }
15 |
16 | const debounced = ref(value.value)
17 |
18 | const updater = useDebounceFn(
19 | () => {
20 | debounced.value = value.value
21 | },
22 | ms,
23 | options
24 | )
25 |
26 | watch(value, () => updater())
27 |
28 | return debounced
29 | }
30 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useTimeoutFn/README.md:
--------------------------------------------------------------------------------
1 | # useTimeoutFn
2 |
3 | 定时器方法
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useTimeoutFn } from '@/uni_modules/tob-use'
11 |
12 | const {
13 | stop,
14 | start,
15 | isPending,
16 | } = useTimeoutFn(() => {
17 | // 你希望执行的函数
18 | }, 3000)
19 | ```
20 |
21 |
22 |
23 | ### 立即开始
24 |
25 | ```js
26 | import { useTimeoutFn } from '@/uni_modules/tob-use'
27 |
28 | const instance = useTimeoutFn(() => {
29 | // 你希望执行的函数
30 | }, 3000, {
31 | immediate: false // 立即开始,默认为 true
32 | })
33 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/makeDestructurable/README.md:
--------------------------------------------------------------------------------
1 | # makeDestructurable
2 |
3 | 使得更好分解
4 |
5 | 即让结果可以使用对象解构或数组解构两种方式
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { makeDestructurable } from '@/uni_modules/tob-use'
12 |
13 | const bar = 1024
14 | const foo = { name: 'foo' }
15 |
16 | const obj = makeDestructurable(
17 | { foo, bar },
18 | [ foo, bar ]
19 | )
20 | ```
21 |
22 | 使用时就可以用数组解构或对象解构了 👇
23 |
24 | ```ts
25 | // 对象解构
26 | let { foo, bar } = obj
27 | ```
28 |
29 | 或者
30 |
31 | ```ts
32 | // 数组解构
33 | let [ foo, bar ] = obj
34 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/and.md:
--------------------------------------------------------------------------------
1 | # and
2 |
3 | AND 判断
4 |
5 | 当所有参数都为 [Truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy) 时,才为 [Truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy)。
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref, watch } from 'vue'
11 | import { and } from '@/uni_modules/tob-use'
12 |
13 | // 支持 ref 包裹的参数
14 | const foo = ref(false)
15 | const bar = ref(true)
16 |
17 | const result = and(foo, bar) // 返回一个计算属性结果
18 |
19 | watch(result, (v) => {
20 | // 只有当 foo 和 bar 的 value 都为 true 时,才输出 true
21 | console.log(v)
22 | })
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/shared/base.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 空函数
3 | */
4 | export const noop = () => {}
5 |
6 | /**
7 | * 事件
8 | */
9 | export const events = new Map()
10 |
11 | /**
12 | * 时间戳获取
13 | */
14 | export const timestamp = () => +Date.now()
15 |
16 | /**
17 | * Promise 型定时器
18 | */
19 | export function promiseTimeout(
20 | ms,
21 | throwOnTimeout = false,
22 | reason = 'Timeout'
23 | ) {
24 | return new Promise((resolve, reject) => {
25 | if (throwOnTimeout) {
26 | setTimeout(() => reject(reason), ms)
27 | } else {
28 | setTimeout(resolve, ms)
29 | }
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/biSyncRef/README.md:
--------------------------------------------------------------------------------
1 | # biSyncRef
2 |
3 | 双向同步
4 |
5 | 同步两个 `ref` 参数
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { biSyncRef } from '@/uni_modules/tob-use'
12 |
13 | const a = ref('a')
14 | const b = ref('b')
15 |
16 | const stop = biSyncRef(a, b)
17 |
18 | console.log(a.value) // a
19 |
20 | b.value = 'foo'
21 |
22 | console.log(a.value) // foo
23 |
24 | a.value = 'bar'
25 |
26 | console.log(b.value) // bar
27 |
28 | stop() // 停止同步
29 |
30 | a.value = 'foo'
31 |
32 | console.log(b.value) // 仍然是 bar
33 | ```
34 |
35 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/state/useStorage/guess.js:
--------------------------------------------------------------------------------
1 | export function guessSerializerType(rawInit) {
2 | return rawInit == null
3 | ? 'any'
4 | : rawInit instanceof Set
5 | ? 'set'
6 | : rawInit instanceof Map
7 | ? 'map'
8 | : rawInit instanceof Date
9 | ? 'date'
10 | : typeof rawInit === 'boolean'
11 | ? 'boolean'
12 | : typeof rawInit === 'string'
13 | ? 'string'
14 | : typeof rawInit === 'object'
15 | ? 'object'
16 | : Array.isArray(rawInit)
17 | ? 'object'
18 | : !Number.isNaN(rawInit)
19 | ? 'number'
20 | : 'any'
21 | }
22 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/and/README.md:
--------------------------------------------------------------------------------
1 | # and
2 |
3 | AND 判断
4 |
5 | 当所有参数都为 [Truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy) 时,才为 [Truthy](https://developer.mozilla.org/zh-CN/docs/Glossary/Truthy)。
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref, watch } from 'vue'
11 | import { and } from '@/uni_modules/tob-use'
12 |
13 | // 支持 ref 包裹的参数
14 | const foo = ref(false)
15 | const bar = ref(true)
16 |
17 | const result = and(foo, bar) // 返回一个计算属性结果
18 |
19 | watch(result, (v) => {
20 | // 只有当 foo 和 bar 的 value 都为 true 时,才输出 true
21 | console.log(v)
22 | })
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useCounter/index.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | /**
4 | * 计数器
5 | */
6 | export const useCounter = (initialValue = 0) => {
7 | const count = ref(initialValue)
8 |
9 | // 递增
10 | const inc = (delta = 1) => (count.value += delta)
11 | // 递减
12 | const dec = (delta = 1) => (count.value -= delta)
13 | // 获取
14 | const get = () => count.value
15 | // 设置
16 | const set = val => (count.value = val)
17 | // 重置
18 | const reset = (val = initialValue) => {
19 | initialValue = val
20 | return set(val)
21 | }
22 |
23 | return { count, inc, dec, get, set, reset }
24 | }
25 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useThrottle/index.js:
--------------------------------------------------------------------------------
1 | import { ref, watch } from 'vue'
2 | import { useThrottleFn } from '../useThrottleFn'
3 |
4 | /**
5 | * 使用节流 ref
6 | */
7 | export const useThrottle = (
8 | value,
9 | delay = 200,
10 | trailing = true,
11 | leading = true
12 | ) => {
13 | if (delay <= 0) {
14 | return value
15 | }
16 |
17 | const throttled = ref(value.value)
18 |
19 | const updater = useThrottleFn(
20 | () => {
21 | throttled.value = value.value
22 | },
23 | delay,
24 | trailing,
25 | leading
26 | )
27 |
28 | watch(value, () => updater())
29 |
30 | return throttled
31 | }
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/shared/is.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 范围限定
3 | */
4 | export const clamp = (n, min, max) => {
5 | return Math.min(max, Math.max(min, n))
6 | }
7 |
8 | /**
9 | * 是否是布尔类型
10 | */
11 | export const isBoolean = v => typeof v === 'boolean'
12 |
13 | /**
14 | * 是否是函数类型
15 | */
16 | export const isFunction = v => typeof v === 'function'
17 |
18 | /**
19 | * 是否是字符串类型
20 | */
21 | export const isString = v => typeof v === 'string'
22 |
23 | /**
24 | * 是否是数字类型
25 | */
26 | export const isNumber = v => typeof v === 'number'
27 |
28 | /**
29 | * 是否未定义
30 | */
31 | export const isUndefined = v => typeof v === 'undefined'
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/makeDestructurable/index.js:
--------------------------------------------------------------------------------
1 | import { isUndefined } from '../../shared/is'
2 |
3 | /**
4 | * 使得更好分解
5 | */
6 | export const makeDestructurable = (obj, arr) => {
7 | if (!isUndefined(Symbol)) {
8 | const clone = { ...obj }
9 |
10 | Object.defineProperty(clone, Symbol.iterator, {
11 | enumerable: false,
12 | value() {
13 | let index = 0
14 | return {
15 | next: () => ({
16 | value: arr[index++],
17 | done: index > arr.length
18 | })
19 | }
20 | }
21 | })
22 |
23 | return clone
24 | } else {
25 | return Object.assign([...arr], obj)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/docs/api/utilities/toRefs.md:
--------------------------------------------------------------------------------
1 | # toRefs
2 |
3 | 扩展之后的 toRefs,允许接受对象型的 ref
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { toRefs } from '@/uni_modules/tob-use'
10 |
11 | const obj = reactive({ a: 'a', b: 0 })
12 | const arr = reactive(['c', 0])
13 |
14 | const { a, b } = toRefs(obj)
15 | const [ c, d ] = toRefs(arr)
16 | ```
17 |
18 | `ref` 类型的也支持
19 |
20 | ```ts
21 | import { ref } from 'vue'
22 | import { toRefs } from '@/uni_modules/tob-use'
23 |
24 | const objRef = ref({ a: 'a', b: 0 })
25 | const arrRef = ref(['c', 0])
26 |
27 | const { a, b } = toRefs(objRef)
28 | const [ c, d ] = toRefs(arrRef)
29 | ```
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | heroText: tob-use
4 | tagline: uniapp 的高效 use 库
5 | actions:
6 | - text: Get Started 👉
7 | link: /guide/
8 | - text: install
9 | link: /guide/start/
10 | type: secondary
11 | features:
12 | - title: 🦖 功能丰富
13 | details: 60+ 的功能供你选择
14 | - title: 🦕 按需加载
15 | details: 让你的应用体积更小
16 | - title: 🐊 灵活可配置
17 | details: 可配置的事件过滤器
18 | - title: 🐳 支持多端
19 | details: 支持 app,h5 和 小程序
20 | - title: 🐬 composition
21 | details: 完全由 composition-api 构建
22 | - title: 🐟 vue3
23 | details: 支持最现代化的 vue3 版本
24 | footer: --- thanks for vueuse 🤗 ---
25 | ---
26 |
27 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchAtMost/index.js:
--------------------------------------------------------------------------------
1 | import { nextTick, ref, unref } from 'vue'
2 | import { watchWithFilter } from '../../shared/filters'
3 |
4 | /**
5 | * 限制次数型监听
6 | */
7 | export const watchAtMost = (source, cb, options = {}) => {
8 | const { count, ...watchOptions } = options
9 |
10 | const current = ref(0)
11 |
12 | const stop = watchWithFilter(
13 | source,
14 | (...args) => {
15 | current.value += 1
16 | // 到达指定次数后暂停副作用并触发回调
17 | if (current.value >= unref(count)) {
18 | nextTick(stop)
19 | }
20 | cb(...args)
21 | },
22 | watchOptions
23 | )
24 |
25 | return { count: current, stop }
26 | }
27 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/toRefs/README.md:
--------------------------------------------------------------------------------
1 | # toRefs
2 |
3 | 扩展之后的 toRefs,允许接受对象型的 ref
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { toRefs } from '@/uni_modules/tob-use'
10 |
11 | const obj = reactive({ a: 'a', b: 0 })
12 | const arr = reactive(['c', 0])
13 |
14 | const { a, b } = toRefs(obj)
15 | const [ c, d ] = toRefs(arr)
16 | ```
17 |
18 | `ref` 类型的也支持
19 |
20 | ```ts
21 | import { ref } from 'vue'
22 | import { toRefs } from '@/uni_modules/tob-use'
23 |
24 | const objRef = ref({ a: 'a', b: 0 })
25 | const arrRef = ref(['c', 0])
26 |
27 | const { a, b } = toRefs(objRef)
28 | const [ c, d ] = toRefs(arrRef)
29 | ```
--------------------------------------------------------------------------------
/.hbuilderx/launch.json:
--------------------------------------------------------------------------------
1 | { // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
2 | // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
3 | "version": "0.0",
4 | "configurations": [{
5 | "app-plus" :
6 | {
7 | "launchtype" : "local"
8 | },
9 | "default" :
10 | {
11 | "launchtype" : "local"
12 | },
13 | "h5" :
14 | {
15 | "launchtype" : "local"
16 | },
17 | "mp-weixin" :
18 | {
19 | "launchtype" : "local"
20 | },
21 | "type" : "uniCloud"
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useTimeout/index.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 | import { noop } from '../../shared/base'
3 | import { useTimeoutFn } from '../useTimeoutFn'
4 |
5 | /**
6 | * 定时器
7 | */
8 | export const useTimeout = (
9 | interval = 1000,
10 | options = {}
11 | ) => {
12 | const { controls: exposeControls = false } = options
13 |
14 | const controls = useTimeoutFn(noop, interval, options)
15 |
16 | // 定时器触发完成标志
17 | const ready = computed(() => !controls.isPending.value)
18 |
19 | // 暴露定时器控制权
20 | if (exposeControls) {
21 | return {
22 | ready,
23 | ...controls
24 | }
25 | } else {
26 | return ready
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docs/guide/start.md:
--------------------------------------------------------------------------------
1 | # 开始
2 |
3 | ## IDE
4 |
5 | ### 1. 安装
6 |
7 | 如果你是直接使用 `HBuilderx` 这个 `IDE` 进行开发的,你可以通过 👉 [插件市场](https://ext.dcloud.net.cn/plugin?id=7308) 直接导入插件。
8 |
9 | 
10 |
11 |
12 |
13 | ### 2. 使用
14 |
15 | 直接从 `@/uni_modules/tob-use` 引入即可。
16 |
17 | ```html
18 |
24 |
25 |
26 |
27 | 我是结果 {{count}}
28 |
29 |
30 | ```
31 |
32 | 更多 `api` 可见 👉 [API 参考](/api/utilities/and)
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useToggle/index.js:
--------------------------------------------------------------------------------
1 | import { ref, isRef } from 'vue'
2 | import { isBoolean } from '../../shared/is'
3 |
4 | /**
5 | * 切换
6 | */
7 | export const useToggle = (initialValue = false) => {
8 | if (isRef(initialValue)) {
9 | return value => {
10 | initialValue.value = isBoolean(value)
11 | ? value
12 | : !initialValue.value
13 | return initialValue.value
14 | }
15 | } else {
16 | const boolean = ref(initialValue)
17 | const toggle = value => {
18 | boolean.value = isBoolean(value)
19 | ? value
20 | : !boolean.value
21 | return boolean.value
22 | }
23 |
24 | return [boolean, toggle]
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useInterval/index.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 | import { useIntervalFn } from '../useIntervalFn'
3 |
4 | /**
5 | * 间隔
6 | */
7 | export const useInterval = (
8 | interval = 1000,
9 | options = {}
10 | ) => {
11 | const {
12 | controls: exposeControls = false,
13 | immediate = true
14 | } = options
15 |
16 | const counter = ref(0)
17 | // 调用间隔循环函数
18 | const controls = useIntervalFn(
19 | () => (counter.value += 1),
20 | interval,
21 | { immediate }
22 | )
23 |
24 | // 暴露控制权
25 | if (exposeControls) {
26 | return {
27 | counter,
28 | ...controls
29 | }
30 | } else {
31 | return counter
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docs/api/utilities/useEventBus.md:
--------------------------------------------------------------------------------
1 | # useEventBus
2 |
3 | 使用事件 bus
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useEventBus } from '@/uni_modules/tob-use'
10 |
11 | const bus = useEventBus('news')
12 |
13 | const listener = (event) => {
14 | console.log(`事件: ${event}`)
15 | }
16 |
17 | // 监听,返回取消订阅函数
18 | const unsubscribe = bus.on(listener)
19 |
20 | // 触发
21 | bus.emit('触发') // 输出 '事件: 触发'
22 |
23 | // 卸载之前注册的事件回调
24 | unsubscribe()
25 | // 或者用 bus.off
26 | bus.off(listener)
27 |
28 | bus.once(() => console.log('一次性事件'))
29 |
30 | bus.emit() // 输出: 一次性事件
31 |
32 | bus.emit() // 啥都不做
33 |
34 | // 清理所有的事件回调
35 | bus.reset()
36 | ```
37 |
38 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/autoResetRef/index.js:
--------------------------------------------------------------------------------
1 | import { customRef, unref } from 'vue'
2 |
3 | /**
4 | * 自动重置ref
5 | */
6 | export const autoResetRef = (
7 | defaultValue,
8 | afterMs = 10000
9 | ) => {
10 | return customRef((track, trigger) => {
11 | let value
12 | let timer
13 | const resetAfter = () => {
14 | setTimeout(() => {
15 | value = defaultValue
16 | trigger()
17 | }, unref(afterMs))
18 | }
19 |
20 | return {
21 | get() {
22 | track()
23 | return value
24 | },
25 | set(newValue) {
26 | value = newValue
27 | trigger()
28 | clearTimeout(timer)
29 | timer = resetAfter()
30 | }
31 | }
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/docs/api/utilities/useToggle.md:
--------------------------------------------------------------------------------
1 | # useToggle
2 |
3 | 切换
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { useToggle } from '@/uni_modules/tob-use'
9 |
10 | const [state, toggle] = useToggle()
11 |
12 | state.value // false
13 |
14 | toggle()
15 |
16 | state.value // true
17 |
18 | toggle(true)
19 |
20 | state.value // true
21 | ```
22 |
23 | 当传入一个 `ref` 时,`useToggle` 将只返回 `toggle` 函数 👇
24 |
25 | ```ts
26 | import { useToggle } from '@/uni_modules/tob-use'
27 |
28 | const state = ref(false)
29 |
30 | const toggle = useToggle(state)
31 |
32 | state.value // false
33 |
34 | toggle()
35 |
36 | state.value // true
37 |
38 | toggle(true)
39 |
40 | state.value // true
41 | ```
42 |
--------------------------------------------------------------------------------
/docs/api/utilities/controlledComputed.md:
--------------------------------------------------------------------------------
1 | # controlledComputed
2 |
3 | 受控型计算属性
4 |
5 | 只有源更新了,才会触发更新,适合频繁更新的场景。
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { controlledComputed } from '@/uni_modules/tob-use'
12 |
13 | let source = ref('foo')
14 | let counter = ref(0)
15 |
16 | const computedRef = controlledComputed(
17 | source, // 监听源,有点像 watch,支持原生 watch 的各种形式
18 | () => counter.value // 返回值函数,有点像 computed
19 | )
20 |
21 | console.log(computedRef.value) // 0
22 |
23 | counter.value += 1
24 |
25 | console.log(computedRef.value) // 仍然是 0
26 |
27 | source.value = 'bar' // 更新源,才会同步最新的返回值函数
28 |
29 | console.log(computedRef.value) // 1
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useToggle/README.md:
--------------------------------------------------------------------------------
1 | # useToggle
2 |
3 | 切换
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { useToggle } from '@/uni_modules/tob-use'
9 |
10 | const [state, toggle] = useToggle()
11 |
12 | state.value // false
13 |
14 | toggle()
15 |
16 | state.value // true
17 |
18 | toggle(true)
19 |
20 | state.value // true
21 | ```
22 |
23 | 当传入一个 `ref` 时,`useToggle` 将只返回 `toggle` 函数 👇
24 |
25 | ```ts
26 | import { useToggle } from '@/uni_modules/tob-use'
27 |
28 | const state = ref(false)
29 |
30 | const toggle = useToggle()
31 |
32 | state.value // false
33 |
34 | toggle()
35 |
36 | state.value // true
37 |
38 | toggle(true)
39 |
40 | state.value // true
41 | ```
--------------------------------------------------------------------------------
/docs/api/animation/useTimeout.md:
--------------------------------------------------------------------------------
1 | # useTimeout
2 |
3 | 定时器
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useTimeout } from '@/uni_modules/tob-use'
11 |
12 | // 设置间隔,单位为毫秒,默认为 1000 毫秒
13 | const ready = useTimeout(1000) // 1 秒后,ready.value 将变成 true
14 |
15 | ready.value // 一个布尔类型的计算属性
16 | ```
17 |
18 |
19 |
20 | #### 可控制
21 |
22 | ```js
23 | import { useTimeout } from '@/uni_modules/tob-use'
24 |
25 | const {
26 | stop, // 停止,函数
27 | start, // 开启,函数
28 | ready, // 完成,布尔类型的计算属性
29 | } = useTimeout(1000, {
30 | controls: true // 开启控制权
31 | })
32 |
33 | start() // 需要手动开启
34 |
35 | setTimeout(() => {
36 | ready.value // true
37 | }, 2000)
38 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/extendRef.md:
--------------------------------------------------------------------------------
1 | # extendRef
2 |
3 | ref 扩展
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { extendRef } from '@/uni_modules/tob-use'
10 |
11 | const myRef = ref('content')
12 |
13 | const extended = extendRef(myRef, { foo: 'extra data' })
14 |
15 | extended.value === 'content'
16 | extended.foo === 'extra data'
17 | ```
18 |
19 | `ref` 将被解包并且是响应式的
20 |
21 | ```ts
22 | const myRef = ref('content')
23 | const extraRef = ref('extra')
24 |
25 | const extended = extendRef(myRef, { extra: extraRef })
26 |
27 | extended.value === 'content'
28 | extended.extra === 'extra'
29 |
30 | extended.extra = 'new data' // 将触发源更新
31 | extraRef.value === 'new data'
32 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useEventBus/README.md:
--------------------------------------------------------------------------------
1 | # useEventBus
2 |
3 | 使用事件 bus
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useEventBus } from '@/uni_modules/tob-use'
10 |
11 | const bus = useEventBus('news')
12 |
13 | const listener = (event) => {
14 | console.log(`事件: ${event}`)
15 | }
16 |
17 | // 监听,返回取消订阅函数
18 | const unsubscribe = bus.on(listener)
19 |
20 | // 触发
21 | bus.emit('触发') // 输出 '事件: 触发'
22 |
23 | // 卸载之前注册的事件回调
24 | unsubscribe()
25 | // 或者用 bus.off
26 | bus.off(listener)
27 |
28 | bus.once(() => console.log('一次性事件'))
29 |
30 | bus.emit() // 输出: 一次性事件
31 |
32 | bus.emit() // 啥都不做
33 |
34 | // 清理所有的事件回调
35 | bus.reset()
36 | ```
37 |
38 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useTimeout/README.md:
--------------------------------------------------------------------------------
1 | # useTimeout
2 |
3 | 定时器
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useTimeout } from '@/uni_modules/tob-use'
11 |
12 | // 设置间隔,单位为毫秒,默认为 1000 毫秒
13 | const ready = useTimeout(1000) // 1 秒后,ready.value 将变成 true
14 |
15 | ready.value // 一个布尔类型的计算属性
16 | ```
17 |
18 |
19 |
20 | #### 可控制
21 |
22 | ```js
23 | import { useTimeout } from '@/uni_modules/tob-use'
24 |
25 | const {
26 | stop, // 停止,函数
27 | start, // 开启,函数
28 | ready, // 完成,布尔类型的计算属性
29 | } = useTimeout(1000, {
30 | controls: true // 开启控制权
31 | })
32 |
33 | start() // 需要手动开启
34 |
35 | setTimeout(() => {
36 | ready.value // true
37 | }, 2000)
38 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/controlledComputed/README.md:
--------------------------------------------------------------------------------
1 | # controlledComputed
2 |
3 | 受控型计算属性
4 |
5 | 只有源更新了,才会触发更新,适合频繁更新的场景。
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { controlledComputed } from '@/uni_modules/tob-use'
12 |
13 | let source = ref('foo')
14 | let counter = ref(0)
15 |
16 | const computedRef = controlledComputed(
17 | source, // 监听源,有点像 watch,支持原生 watch 的各种形式
18 | () => counter.value // 返回值函数,有点像 computed
19 | )
20 |
21 | console.log(computedRef.value) // 0
22 |
23 | counter.value += 1
24 |
25 | console.log(computedRef.value) // 仍然是 0
26 |
27 | source.value = 'bar' // 更新源,才会同步最新的返回值函数
28 |
29 | console.log(computedRef.value) // 1
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/extendRef/index.js:
--------------------------------------------------------------------------------
1 | import { isRef } from 'vue'
2 |
3 | /**
4 | * ref 扩展
5 | */
6 | export const extendRef = (ref, extend, options = {}) => {
7 | const { enumerable = false, unwrap = true } = options
8 |
9 | for (const [key, value] of Object.entries(extend)) {
10 | if (key === 'value') continue // 忽略 .value 键
11 |
12 | // 保留原有 ref
13 | if (isRef(value) && unwrap) {
14 | Object.defineProperty(ref, key, {
15 | get() {
16 | return value.value
17 | },
18 | set(v) {
19 | value.value = v
20 | },
21 | enumerable
22 | })
23 | } else {
24 | Object.defineProperty(ref, key, { value, enumerable })
25 | }
26 | }
27 | return ref
28 | }
29 |
--------------------------------------------------------------------------------
/uni_modules/tob-less/readme.md:
--------------------------------------------------------------------------------
1 | # tob-less
2 |
3 | ## 介绍 👀
4 |
5 | 一个主题驱动的 **uniapp** 样式库
6 |
7 |
8 |
9 |
10 |
11 | ## 特点 👍
12 |
13 | 1. 原子的
14 | - 开发效率直接翻一番
15 | 2. 主题驱动
16 | - 自定义主题,满足个性化需求
17 | 3. 支持Mixins
18 | - 语义化的模板,更清晰的结构
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## 文档 😋
26 |
27 | [tob-less 文档](https://tob-less.netlify.app/)
28 |
29 |
30 |
31 |
32 |
33 | ## 启发 😀
34 |
35 | 该库受以下技术启发
36 |
37 | - [Less](https://less.bootcss.com/)
38 | - [Css 变量](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties)
39 | - [Windicss](https://cn.windicss.org/)
40 | - [Tailwindcss](https://www.tailwindcss.cn/)
41 |
42 |
--------------------------------------------------------------------------------
/docs/api/animation/useIntervalFn.md:
--------------------------------------------------------------------------------
1 | # useIntervalFn
2 |
3 | 使用间隔函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useIntervalFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置间隔,单位为毫秒,默认为 1000 毫秒
12 | const { pause, resume, isActive } = useIntervalFn(() => {
13 | // 你希望执行的函数
14 | }, 1000)
15 |
16 | isActive.value // 是否在执行中
17 |
18 | pause() // 暂停
19 |
20 | resume() // 恢复
21 | ```
22 |
23 |
24 |
25 | ### Watch 选项
26 |
27 | ```js
28 | import { useInterval } from '@/uni_modules/tob-use'
29 |
30 | const { pause, resume, isActive } = useIntervalFn(200, {
31 | immediate: false, // 立即开启,默认为 true
32 | immediateCallback: false // 立即触发,不需要等待第一个间隔,默认为 false
33 | })
34 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/extendRef/README.md:
--------------------------------------------------------------------------------
1 | # extendRef
2 |
3 | ref 扩展
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { extendRef } from '@/uni_modules/tob-use'
10 |
11 | const myRef = ref('content')
12 |
13 | const extended = extendRef(myRef, { foo: 'extra data' })
14 |
15 | extended.value === 'content'
16 | extended.foo === 'extra data'
17 | ```
18 |
19 | `ref` 将被解包并且是响应式的
20 |
21 | ```ts
22 | const myRef = ref('content')
23 | const extraRef = ref('extra')
24 |
25 | const extended = extendRef(myRef, { extra: extraRef })
26 |
27 | extended.value === 'content'
28 | extended.extra === 'extra'
29 |
30 | extended.extra = 'new data' // 将触发源更新
31 | extraRef.value === 'new data'
32 | ```
--------------------------------------------------------------------------------
/docs/api/component/tryOnMounted.md:
--------------------------------------------------------------------------------
1 | # tryOnMounted
2 |
3 | 在挂载后触发
4 |
5 | 比原生的 `onMount` 更安全
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { tryOnMounted } from '@/uni_modules/tob-use'
11 |
12 | // 不在组件内,将直接调用
13 | tryOnMounted(() => {
14 | console.log("这将不做任何事情")
15 | })
16 | ```
17 |
18 | ```html
19 |
27 | ```
28 |
29 |
30 |
31 | ### 非同步
32 |
33 | ```js
34 | import { tryOnMounted } from '@/uni_modules/tob-use'
35 |
36 | // 不在组件内,设置第二参数,将在 nextTick 调用
37 | tryOnMounted(() => {
38 | console.log("这将不做任何事情")
39 | }, false)
40 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/controlledComputed/index.js:
--------------------------------------------------------------------------------
1 | import { ref, customRef } from 'vue'
2 |
3 | /**
4 | * 受控型计算属性
5 | */
6 | export const controlledComputed = (source, fn) => {
7 | let v
8 | let track
9 | let trigger
10 | const dirty = ref(true)
11 |
12 | // 只有 source 源改变时才去触发
13 | watch(
14 | source,
15 | () => {
16 | dirty.value = true
17 | trigger()
18 | },
19 | { flush: 'sync' }
20 | )
21 |
22 | return customRef((_track, _trigger) => {
23 | track = _track
24 | trigger = _trigger
25 |
26 | return {
27 | get() {
28 | if (dirty.value) {
29 | v = fn()
30 | dirty.value = false
31 | }
32 | track()
33 | return v
34 | },
35 | set() {}
36 | }
37 | })
38 | }
39 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useIntervalFn/README.md:
--------------------------------------------------------------------------------
1 | # useIntervalFn
2 |
3 | 使用间隔函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useIntervalFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置间隔,单位为毫秒,默认为 1000 毫秒
12 | const { pause, resume, isActive } = useIntervalFn(() => {
13 | // 你希望执行的函数
14 | }, 1000)
15 |
16 | isActive.value // 是否在执行中
17 |
18 | pause() // 暂停
19 |
20 | resume() // 恢复
21 | ```
22 |
23 |
24 |
25 | ### Watch 选项
26 |
27 | ```js
28 | import { useInterval } from '@/uni_modules/tob-use'
29 |
30 | const { pause, resume, isActive } = useIntervalFn(200, {
31 | immediate: false, // 立即开启,默认为 true
32 | immediateCallback: false // 立即触发,不需要等待第一个间隔,默认为 false
33 | })
34 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnMounted/README.md:
--------------------------------------------------------------------------------
1 | # tryOnMounted
2 |
3 | 在挂载后触发
4 |
5 | 比原生的 `onMount` 更安全
6 |
7 | ## Usage
8 |
9 | ```js
10 | import { tryOnMounted } from '@/uni_modules/tob-use'
11 |
12 | // 不在组件内,将直接调用
13 | tryOnMounted(() => {
14 | console.log("这将不做任何事情")
15 | })
16 | ```
17 |
18 | ```html
19 |
27 | ```
28 |
29 |
30 |
31 | ### 非同步
32 |
33 | ```js
34 | import { tryOnMounted } from '@/uni_modules/tob-use'
35 |
36 | // 不在组件内,设置第二参数,将在 nextTick 调用
37 | tryOnMounted(() => {
38 | console.log("这将不做任何事情")
39 | }, false)
40 | ```
--------------------------------------------------------------------------------
/docs/api/watch/watchOnce.md:
--------------------------------------------------------------------------------
1 | # watchOnce
2 |
3 | 一次性监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { watchOnce } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('foo')
14 |
15 | const stop = watchOnce(source, () => {
16 | // 只会触发一次
17 | console.log('source changed!')
18 | })
19 | ```
20 |
21 |
22 |
23 | ### Watch 选项
24 |
25 | ```js
26 | import { ref } from 'vue'
27 | import { watchOnce } from '@/uni_modules/tob-use'
28 |
29 | const source = ref('old')
30 |
31 | const changed = () => console.log('trigger!')
32 |
33 | watchOnce(source, changed, {
34 | deep: true, // 深度同步
35 | immediate: true, // 立即同步,默认为 false
36 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
37 | })
38 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchOnce/README.md:
--------------------------------------------------------------------------------
1 | # watchOnce
2 |
3 | 一次性监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { watchOnce } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('foo')
14 |
15 | const stop = watchOnce(source, () => {
16 | // 只会触发一次
17 | console.log('source changed!')
18 | })
19 | ```
20 |
21 |
22 |
23 | ### Watch 选项
24 |
25 | ```js
26 | import { ref } from 'vue'
27 | import { watchOnce } from '@/uni_modules/tob-use'
28 |
29 | const source = ref('old')
30 |
31 | const changed = () => console.log('trigger!')
32 |
33 | watchOnce(source, changed, {
34 | deep: true, // 深度同步
35 | immediate: true, // 立即同步,默认为 false
36 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
37 | })
38 | ```
--------------------------------------------------------------------------------
/docs/api/watch/whenever.md:
--------------------------------------------------------------------------------
1 | # whenever
2 |
3 | 仅当为真时触发
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { whenever } from '@/uni_modules/tob-use'
12 |
13 | const source = ref(false)
14 |
15 | const changed = () => console.log("触发了")
16 |
17 | const stop = whenever(source, changed)
18 |
19 | source.value = true // 输出 '触发了'
20 | ```
21 |
22 |
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```js
29 | import { ref } from 'vue'
30 | import { whenever } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const changed = () => console.log('trigger!')
35 |
36 | whenever(source, changed, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/computedInject/index.js:
--------------------------------------------------------------------------------
1 | import { computed, inject } from 'vue'
2 | import { isFunction } from '../../shared/is'
3 |
4 | /**
5 | * 计算属性型 inject
6 | */
7 | export const computedInject = (
8 | key,
9 | options,
10 | defaultSource,
11 | treatDefaultAsFactory
12 | ) => {
13 | let source = inject(key)
14 |
15 | if (defaultSource) {
16 | source = inject(key, defaultSource)
17 | }
18 |
19 | // 使得默认值作为工厂函数
20 | if (treatDefaultAsFactory) {
21 | source = inject(
22 | key,
23 | defaultSource,
24 | treatDefaultAsFactory
25 | )
26 | }
27 |
28 |
29 | if (isFunction(options)) {
30 | return computed(ctx => options(source, ctx))
31 | } else {
32 | return computed({
33 | get: ctx => options.get(source, ctx),
34 | set: options.set
35 | })
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/api/utilities/useDebounceFn.md:
--------------------------------------------------------------------------------
1 | # useDebounceFn
2 |
3 | 使用防抖函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useDebounceFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置防抖间隔,单位为毫秒,默认为 200 毫秒
12 | const debouncedFn = useDebounceFn(() => {
13 | console.log('执行了')
14 | }, 1000)
15 |
16 | // 调用多次
17 | debouncedFn()
18 | debouncedFn()
19 | debouncedFn()
20 | debouncedFn()
21 |
22 | setTimeout(() => {
23 | debouncedFn() // 最终只会执行一次,输出 '打印了'
24 | }, 600)
25 | ```
26 |
27 |
28 |
29 | ### 最后期限
30 |
31 | ```ts
32 | import { ref } from 'vue'
33 | import { useDebounceFn } from '@/uni_modules/tob-use'
34 |
35 | // 第三个参数可接受配置
36 | const debouncedFn = useDebounceFn(() => {
37 | console.log('执行了')
38 | }, 1000, {
39 | maxWait: 3000 // 最后期限,不管是否在防抖中,一律触发
40 | })
41 | ```
--------------------------------------------------------------------------------
/docs/api/watch/watchAtMost.md:
--------------------------------------------------------------------------------
1 | # watchAtMost
2 |
3 | 限制次数型监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { watchAtMost } from '@/uni_modules/tob-use'
10 |
11 | const source = ref(1)
12 |
13 | const changed = () => console.log('trigger!')
14 |
15 | const stop = watchAtMost(
16 | source,
17 | changed,
18 | {
19 | count: 3, // 最多触发 3 次
20 | }
21 | )
22 | ```
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```js
29 | import { ref } from 'vue'
30 | import { watchAtMost } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const changed = () => console.log('trigger!')
35 |
36 | watchAtMost(source, changed, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/whenever/README.md:
--------------------------------------------------------------------------------
1 | # whenever
2 |
3 | 仅当为真时触发
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { whenever } from '@/uni_modules/tob-use'
12 |
13 | const source = ref(false)
14 |
15 | const changed = () => console.log("触发了")
16 |
17 | const stop = whenever(source, changed)
18 |
19 | source.value = true // 输出 '触发了'
20 | ```
21 |
22 |
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```js
29 | import { ref } from 'vue'
30 | import { whenever } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const changed = () => console.log('trigger!')
35 |
36 | whenever(source, changed, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactifyObject/index.js:
--------------------------------------------------------------------------------
1 | import { reactify } from '../reactify'
2 | import { isFunction } from '../../shared/is'
3 |
4 | /**
5 | * 对象的响应式转换
6 | */
7 | export const reactifyObject = (obj, optionsOrKeys = {}) => {
8 | let keys = []
9 | if (Array.isArray(optionsOrKeys)) {
10 | keys = optionsOrKeys
11 | } else {
12 | const { includeOwnProperties = true } = optionsOrKeys
13 |
14 | keys.push(...Object.keys(obj))
15 | if (includeOwnProperties) {
16 | keys.push(...Object.getOwnPropertyNames(obj))
17 | }
18 | }
19 |
20 | return Object.fromEntries(
21 | keys.map(key => {
22 | const value = obj[key]
23 | return [
24 | key,
25 | // 将对象上所有的函数转换为解除 ref 参数的函数
26 | isFunction(value)
27 | ? reactify(value.bind(obj))
28 | : value
29 | ]
30 | })
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useDebounceFn/README.md:
--------------------------------------------------------------------------------
1 | # useDebounceFn
2 |
3 | 使用防抖函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useDebounceFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置防抖间隔,单位为毫秒,默认为 200 毫秒
12 | const debouncedFn = useDebounceFn(() => {
13 | console.log('执行了')
14 | }, 1000)
15 |
16 | // 调用多次
17 | debouncedFn()
18 | debouncedFn()
19 | debouncedFn()
20 | debouncedFn()
21 |
22 | setTimeout(() => {
23 | debouncedFn() // 最终只会执行一次,输出 '打印了'
24 | }, 600)
25 | ```
26 |
27 |
28 |
29 | ### 最后期限
30 |
31 | ```ts
32 | import { ref } from 'vue'
33 | import { useDebounceFn } from '@/uni_modules/tob-use'
34 |
35 | // 第三个参数可接受配置
36 | const debouncedFn = useDebounceFn(() => {
37 | console.log('执行了')
38 | }, 1000, {
39 | maxWait: 3000 // 最后期限,不管是否在防抖中,一律触发
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchAtMost/README.md:
--------------------------------------------------------------------------------
1 | # watchAtMost
2 |
3 | 限制次数型监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { watchAtMost } from '@/uni_modules/tob-use'
10 |
11 | const source = ref(1)
12 |
13 | const changed = () => console.log('trigger!')
14 |
15 | const stop = watchAtMost(
16 | source,
17 | changed,
18 | {
19 | count: 3, // 最多触发 3 次
20 | }
21 | )
22 | ```
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```js
29 | import { ref } from 'vue'
30 | import { watchAtMost } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const changed = () => console.log('trigger!')
35 |
36 | watchAtMost(source, changed, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/docs/.vuepress/components/eagerComputed2.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 | 点击 👉
25 |
26 |
29 |
30 |
复杂计算属性更新次数: {{ complexUpdatedCount }}
31 |
32 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/toRefs/index.js:
--------------------------------------------------------------------------------
1 | import { toRefs as _toRefs, customRef, isRef } from 'vue'
2 |
3 | /**
4 | * 扩展之后的 toRefs,允许接受对象型的 ref
5 | */
6 | export const toRefs = objectRef => {
7 | if (!isRef(objectRef)) return _toRefs(objectRef)
8 |
9 | const result = Array.isArray(objectRef.value)
10 | ? new Array(objectRef.value.length)
11 | : {}
12 |
13 | for (const key in objectRef.value) {
14 | result[key] = customRef(() => ({
15 | get() {
16 | return objectRef.value[key]
17 | },
18 | set(v) {
19 | if (Array.isArray(objectRef.value)) {
20 | const copy = [...objectRef.value]
21 | copy[key] = v
22 | objectRef.value = copy
23 | } else {
24 | objectRef.value = {
25 | ...objectRef.value,
26 | [key]: v
27 | }
28 | }
29 | }
30 | }))
31 | }
32 | return result
33 | }
34 |
--------------------------------------------------------------------------------
/docs/api/component/tryOnScopeDispose.md:
--------------------------------------------------------------------------------
1 | # tryOnScopeDispose
2 |
3 | 尝试获取 `effect` 区域内的副作用
4 |
5 | 这是一个较为底层的 `api`,需要你对 `effect` 作用域有非常好的理解。
6 |
7 | 大多数情况下,它相当于 [tryOnUnmounted](/api/component/tryOnUnmounted)
8 |
9 | ## Usage
10 |
11 | ```js
12 | import { tryOnScopeDispose } from '@/uni_modules/tob-use'
13 |
14 | // 不在组件内,将不会注册回调,并返回 false
15 | const result = tryOnScopeDispose(() => {
16 | console.log("这将不做任何事情")
17 | })
18 |
19 | result // false
20 | ```
21 |
22 | ```html
23 |
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/tryOnScopeDispose/README.md:
--------------------------------------------------------------------------------
1 | # tryOnScopeDispose
2 |
3 | 尝试获取 `effect` 区域内的副作用
4 |
5 | 这是一个较为底层的 `api`,需要你对 `effect` 作用域有非常好的理解。
6 |
7 | 大多数情况下,它相当于 [tryOnUnmounted](/api/component/tryOnUnmounted)
8 |
9 | ## Usage
10 |
11 | ```js
12 | import { tryOnScopeDispose } from '@/uni_modules/tob-use'
13 |
14 | // 不在组件内,将不会注册回调,并返回 false
15 | const result = tryOnScopeDispose(() => {
16 | console.log("这将不做任何事情")
17 | })
18 |
19 | result // false
20 | ```
21 |
22 | ```html
23 |
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/uni_modules/tob-less/index.js:
--------------------------------------------------------------------------------
1 | const appTheme = uni.getStorageSync('AppTheme') || ''
2 |
3 | // #ifdef VUE2
4 | import Vue from 'vue'
5 | const shared = Vue.observable({ appTheme })
6 | // #endif
7 |
8 | // #ifdef VUE3
9 | import { reactive } from 'vue'
10 | const shared = reactive({ appTheme })
11 | // #endif
12 |
13 | export default (V, options = {}) => {
14 | const { initAppTheme = '' } = options
15 |
16 | shared.appTheme = shared.appTheme
17 | ? shared.appTheme
18 | : initAppTheme
19 |
20 | V.mixin({
21 | computed: {
22 | // app主题
23 | AppTheme() {
24 | const { appTheme } = shared
25 | const AppTheme = appTheme ? `theme-${appTheme}` : ''
26 | uni.setStorageSync('AppTheme', AppTheme)
27 | return AppTheme
28 | }
29 | },
30 | methods: {
31 | // 切换app主题
32 | ToggleAppTheme(t) {
33 | shared.appTheme = t
34 | }
35 | }
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/docs/api/utilities/useDebounce.md:
--------------------------------------------------------------------------------
1 | # useDebounce
2 |
3 | 使用防抖 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useDebounce } from '@/uni_modules/tob-use'
12 |
13 | const input = ref('foo')
14 |
15 | // 第二个参数设置防抖间隔,单位为毫秒,默认为 200 毫秒
16 | const debounced = useDebounce(input, 1000)
17 |
18 | // 频繁的更新
19 | input.value = 'jack'
20 | input.value = 'tom'
21 | input.value = 'bar'
22 |
23 | // 仍然是 foo
24 | console.log(debounced.value)
25 |
26 | setTimeout(() => {
27 | // 只有最有一个生效,bar
28 | console.log(debounced.value)
29 | }, 2000)
30 | ```
31 |
32 |
33 |
34 | ### 最后期限
35 |
36 | ```ts
37 | import { ref } from 'vue'
38 | import { useDebounce } from '@/uni_modules/tob-use'
39 |
40 | const input = ref('foo')
41 |
42 | // 第三个参数可接受配置
43 | const debounced = useDebounce(input, 1000, {
44 | maxWait: 3000 // 最后期限,不管是否在防抖中,一律触发
45 | })
46 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useDebounce/README.md:
--------------------------------------------------------------------------------
1 | # useDebounce
2 |
3 | 使用防抖 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useDebounce } from '@/uni_modules/tob-use'
12 |
13 | const input = ref('foo')
14 |
15 | // 第二个参数设置防抖间隔,单位为毫秒,默认为 200 毫秒
16 | const debounced = useDebounce(input, 1000)
17 |
18 | // 频繁的更新
19 | input.value = 'jack'
20 | input.value = 'tom'
21 | input.value = 'bar'
22 |
23 | // 仍然是 foo
24 | console.log(debounced.value)
25 |
26 | setTimeout(() => {
27 | // 只有最有一个生效,bar
28 | console.log(debounced.value)
29 | }, 2000)
30 | ```
31 |
32 |
33 |
34 | ### 最后期限
35 |
36 | ```ts
37 | import { ref } from 'vue'
38 | import { useDebounce } from '@/uni_modules/tob-use'
39 |
40 | const input = ref('foo')
41 |
42 | // 第三个参数可接受配置
43 | const debounced = useDebounce(input, 1000, {
44 | maxWait: 3000 // 最后期限,不管是否在防抖中,一律触发
45 | })
46 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/useThrottle.md:
--------------------------------------------------------------------------------
1 | # useThrottle
2 |
3 | 使用节流 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useThrottle } from '@/uni_modules/tob-use'
12 |
13 | const input = ref('')
14 |
15 | // 第二个参数设置节流间隔,单位为毫秒,默认为 200 毫秒
16 | const throttled = useThrottle(input, 1000)
17 | ```
18 |
19 |
20 |
21 | ### Trailing
22 |
23 | 如果您不想让尾随更改,即确保时间到达后触发,可以设置第三个参数为 `false`,默认为 `true`
24 |
25 | ```ts
26 | import { ref } from 'vue'
27 | import { useThrottle } from '@/uni_modules/tob-use'
28 |
29 | const input = ref('')
30 | const throttled = useThrottle(input, 1000, false)
31 | ```
32 |
33 |
34 |
35 | ### Leading
36 |
37 | 如果你不想一上来就执行,可以设置第四个参数为 `false`,默认为 `true`
38 |
39 | ```ts
40 | import { ref } from 'vue'
41 | import { useThrottle } from '@/uni_modules/tob-use'
42 |
43 | const input = ref('')
44 | const throttled = useThrottle(input, 1000, true, false)
45 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/toReactive/index.js:
--------------------------------------------------------------------------------
1 | import { isRef, reactive } from 'vue'
2 |
3 | /**
4 | * 转化为 Reactive
5 | */
6 | export const toReactive = objectRef => {
7 | if (!isRef(objectRef)) {
8 | return reactive(objectRef)
9 | }
10 |
11 | const proxy = new Proxy(
12 | {},
13 | {
14 | get(_, p, receiver) {
15 | return Reflect.get(objectRef.value, p, receiver)
16 | },
17 | set(_, p, value) {
18 | objectRef.value[p] = value
19 | return true
20 | },
21 | deleteProperty(_, p) {
22 | return Reflect.deleteProperty(objectRef.value, p)
23 | },
24 | has(_, p) {
25 | return Reflect.has(objectRef.value, p)
26 | },
27 | ownKeys() {
28 | return Object.keys(objectRef.value)
29 | },
30 | getOwnPropertyDescriptor() {
31 | return {
32 | enumerable: true,
33 | configurable: true
34 | }
35 | }
36 | }
37 | )
38 |
39 | return reactive(proxy)
40 | }
41 |
--------------------------------------------------------------------------------
/docs/api/utilities/useCycleList.md:
--------------------------------------------------------------------------------
1 | # useCycleList
2 |
3 | 环表
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useCycleList } from '@/uni_modules/tob-use'
11 |
12 | const { state, next, prev, index } = useCycleList([
13 | 'Dog',
14 | 'Cat',
15 | 'Lizard',
16 | ])
17 |
18 | state.value // 'Dog'
19 | index.value // 0
20 |
21 | prev() // 上一个
22 | state.value // 'Lizard'
23 | index.value // 2
24 |
25 | next() // 下一个
26 | state.value // 'Dog'
27 | index.value // 0
28 |
29 | next(2) // 下两个
30 | state.value // 'Lizard'
31 |
32 | prev(2) // 上两个
33 | state.value // 'Dog'
34 | ```
35 |
36 |
37 |
38 | ### 初始值
39 |
40 | ```ts
41 | import { useCycleList } from '@/uni_modules/tob-use'
42 |
43 | const { state, next, prev } = useCycleList([
44 | 'Dog',
45 | 'Cat',
46 | 'Lizard',
47 | ], { initialValue: 'init' })
48 |
49 | state.value // 'init'
50 |
51 | next() // 下一个
52 |
53 | state.value // 'Dog'
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/api/watch/watchWithFilter.md:
--------------------------------------------------------------------------------
1 | # watchWithFilter
2 |
3 | 带过滤器的监听
4 |
5 | 这是一个较为底层的 `api`,大多数情况你不需要它,除非你要进行特别的自定义
6 | ## Usage
7 |
8 | ```js
9 | import { ref } from 'vue'
10 | import { watchWithFilter } from '@/uni_modules/tob-use'
11 |
12 | const source = ref('foo')
13 |
14 | const changed = () => console.log('changed!')
15 |
16 | watchWithFilter(
17 | source,
18 | changed,
19 | {
20 | eventFilter(changedHandle) {
21 | changedHandle() // 就是上边的 changed
22 | }
23 | }
24 | )
25 | ```
26 |
27 |
28 |
29 | ### Watch 选项
30 |
31 | ```js
32 | import { ref } from 'vue'
33 | import { watchOnce } from '@/uni_modules/tob-use'
34 |
35 | const source = ref('old')
36 |
37 | const changed = () => console.log('trigger!')
38 |
39 | watchWithFilter(source, changed, {
40 | deep: true, // 深度同步
41 | immediate: true, // 立即同步,默认为 false
42 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
43 | })
44 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useThrottle/README.md:
--------------------------------------------------------------------------------
1 | # useThrottle
2 |
3 | 使用节流 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useThrottle } from '@/uni_modules/tob-use'
12 |
13 | const input = ref('')
14 |
15 | // 第二个参数设置节流间隔,单位为毫秒,默认为 200 毫秒
16 | const throttled = useThrottle(input, 1000)
17 | ```
18 |
19 |
20 |
21 | ### Trailing
22 |
23 | 如果您不想让尾随更改,即确保时间到达后触发,可以设置第三个参数为 `false`,默认为 `true`
24 |
25 | ```ts
26 | import { ref } from 'vue'
27 | import { useThrottle } from '@/uni_modules/tob-use'
28 |
29 | const input = ref('')
30 | const throttled = useThrottle(input, 1000, false)
31 | ```
32 |
33 |
34 |
35 | ### Leading
36 |
37 | 如果你不想一上来就执行,可以设置第四个参数为 `false`,默认为 `true`
38 |
39 | ```ts
40 | import { ref } from 'vue'
41 | import { useThrottle } from '@/uni_modules/tob-use'
42 |
43 | const input = ref('')
44 | const throttled = useThrottle(input, 1000, true, false)
45 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/watchWithFilter/README.md:
--------------------------------------------------------------------------------
1 | # watchWithFilter
2 |
3 | 带过滤器的监听
4 |
5 | 这是一个较为底层的 `api`,大多数情况你不需要它,除非你要进行特别的自定义
6 | ## Usage
7 |
8 | ```js
9 | import { ref } from 'vue'
10 | import { watchWithFilter } from '@/uni_modules/tob-use'
11 |
12 | const source = ref('foo')
13 |
14 | const changed = () => console.log('changed!')
15 |
16 | watchWithFilter(
17 | source,
18 | changed,
19 | {
20 | eventFilter(changedHandle) {
21 | changedHandle() // 就是上边的 changed
22 | }
23 | }
24 | )
25 | ```
26 |
27 |
28 |
29 | ### Watch 选项
30 |
31 | ```js
32 | import { ref } from 'vue'
33 | import { watchOnce } from '@/uni_modules/tob-use'
34 |
35 | const source = ref('old')
36 |
37 | const changed = () => console.log('trigger!')
38 |
39 | watchWithFilter(source, changed, {
40 | deep: true, // 深度同步
41 | immediate: true, // 立即同步,默认为 false
42 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
43 | })
44 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useCycleList/README.md:
--------------------------------------------------------------------------------
1 | # useCycleList
2 |
3 | 环表
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useCycleList } from '@/uni_modules/tob-use'
11 |
12 | const { state, next, prev, index } = useCycleList([
13 | 'Dog',
14 | 'Cat',
15 | 'Lizard',
16 | ])
17 |
18 | state.value // 'Dog'
19 | index.value // 0
20 |
21 | prev() // 上一个
22 | state.value // 'Lizard'
23 | index.value // 2
24 |
25 | next() // 下一个
26 | state.value // 'Dog'
27 | index.value // 0
28 |
29 | next(2) // 下两个
30 | state.value // 'Lizard'
31 |
32 | prev(2) // 上两个
33 | state.value // 'Dog'
34 | ```
35 |
36 |
37 |
38 | ### 初始值
39 |
40 | ```ts
41 | import { useCycleList } from '@/uni_modules/tob-use'
42 |
43 | const { state, next, prev } = useCycleList([
44 | 'Dog',
45 | 'Cat',
46 | 'Lizard',
47 | ], { initialValue: 'init' })
48 |
49 | state.value // 'init'
50 |
51 | next() // 下一个
52 |
53 | state.value // 'Dog'
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/api/utilities/useThrottleFn.md:
--------------------------------------------------------------------------------
1 | # useThrottleFn
2 |
3 | 使用节流函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useThrottleFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置节流间隔,单位为毫秒,默认为 200 毫秒
12 | const throttledFn = useThrottleFn(() => {
13 | console.log('执行了')
14 | }, 1000)
15 |
16 | throttledFn()
17 | ```
18 |
19 |
20 |
21 | ### Trailing
22 |
23 | 如果您不想让尾随更改,即确保时间到达后触发,可以设置第三个参数为 `false`,默认为 `true`
24 |
25 | ```ts
26 | import { ref } from 'vue'
27 | import { useThrottle } from '@/uni_modules/tob-use'
28 |
29 | const throttledFn = useThrottleFn(() => {
30 | console.log('执行了')
31 | }, 1000, false)
32 | ```
33 |
34 |
35 |
36 | ### Leading
37 |
38 | 如果你不想一上来就执行,可以设置第四个参数为 `false`,默认为 `true`
39 |
40 | ```ts
41 | import { ref } from 'vue'
42 | import { useThrottle } from '@/uni_modules/tob-use'
43 |
44 | const throttledFn = useThrottleFn(() => {
45 | console.log('执行了')
46 | }, 1000, true, false)
47 | ```
48 |
--------------------------------------------------------------------------------
/docs/api/watch/throttledWatch.md:
--------------------------------------------------------------------------------
1 | # throttledWatch
2 |
3 | 节流型监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { throttledWatch } from '@/uni_modules/tob-use'
10 |
11 | const source = ref('old')
12 |
13 | const watchOptions = {
14 | throttle: 500 // 节流间隔,单位为毫秒,默认为 0
15 | }
16 |
17 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
18 |
19 | const stop = throttledWatch(source, watchChanged, watchOptions)
20 |
21 | source.value = 'new'
22 | ```
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```ts
29 | import { ref } from 'vue'
30 | import { throttledWatch } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
35 |
36 | throttledWatch(source, watchChanged, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/throttledWatch/README.md:
--------------------------------------------------------------------------------
1 | # throttledWatch
2 |
3 | 节流型监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { throttledWatch } from '@/uni_modules/tob-use'
10 |
11 | const source = ref('old')
12 |
13 | const watchOptions = {
14 | throttle: 500 // 节流间隔,单位为毫秒,默认为 0
15 | }
16 |
17 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
18 |
19 | const stop = throttledWatch(source, watchChanged, watchOptions)
20 |
21 | source.value = 'new'
22 | ```
23 |
24 |
25 |
26 | ### Watch 选项
27 |
28 | ```ts
29 | import { ref } from 'vue'
30 | import { throttledWatch } from '@/uni_modules/tob-use'
31 |
32 | const source = ref('old')
33 |
34 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
35 |
36 | throttledWatch(source, watchChanged, {
37 | deep: true, // 深度同步
38 | immediate: true, // 立即同步,默认为 false
39 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
40 | })
41 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useThrottleFn/README.md:
--------------------------------------------------------------------------------
1 | # useThrottleFn
2 |
3 | 使用节流函数
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { useThrottleFn } from '@/uni_modules/tob-use'
10 |
11 | // 第二个参数设置节流间隔,单位为毫秒,默认为 200 毫秒
12 | const throttledFn = useThrottleFn(() => {
13 | console.log('执行了')
14 | }, 1000)
15 |
16 | throttledFn()
17 | ```
18 |
19 |
20 |
21 | ### Trailing
22 |
23 | 如果您不想让尾随更改,即确保时间到达后触发,可以设置第三个参数为 `false`,默认为 `true`
24 |
25 | ```ts
26 | import { ref } from 'vue'
27 | import { useThrottle } from '@/uni_modules/tob-use'
28 |
29 | const throttledFn = useThrottleFn(() => {
30 | console.log('执行了')
31 | }, 1000, false)
32 | ```
33 |
34 |
35 |
36 | ### Leading
37 |
38 | 如果你不想一上来就执行,可以设置第四个参数为 `false`,默认为 `true`
39 |
40 | ```ts
41 | import { ref } from 'vue'
42 | import { useThrottle } from '@/uni_modules/tob-use'
43 |
44 | const throttledFn = useThrottleFn(() => {
45 | console.log('执行了')
46 | }, 1000, true, false)
47 | ```
48 |
--------------------------------------------------------------------------------
/docs/api/watch/debouncedWatch.md:
--------------------------------------------------------------------------------
1 | # debouncedWatch
2 |
3 | 防抖监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { debouncedWatch } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('old')
14 |
15 | const watchOptions = {
16 | debounce: 500 // 防抖间隔,单位为毫秒,默认为 0
17 | }
18 |
19 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
20 |
21 | const stop = debouncedWatch(source, watchChanged, watchOptions)
22 |
23 | source.value = 'new' // 500 毫秒后输出 old -> new
24 | ```
25 |
26 |
27 |
28 | ### Watch 选项
29 |
30 | ```ts
31 | import { ref } from 'vue'
32 | import { debouncedWatch } from '@/uni_modules/tob-use'
33 |
34 | const source = ref('old')
35 |
36 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
37 |
38 | debouncedWatch(source, watchChanged, {
39 | deep: true, // 深度同步
40 | immediate: true, // 立即同步,默认为 false
41 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
42 | })
43 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/debouncedWatch/README.md:
--------------------------------------------------------------------------------
1 | # debouncedWatch
2 |
3 | 防抖监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { debouncedWatch } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('old')
14 |
15 | const watchOptions = {
16 | debounce: 500 // 防抖间隔,单位为毫秒,默认为 0
17 | }
18 |
19 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
20 |
21 | const stop = debouncedWatch(source, watchChanged, watchOptions)
22 |
23 | source.value = 'new' // 500 毫秒后输出 old -> new
24 | ```
25 |
26 |
27 |
28 | ### Watch 选项
29 |
30 | ```ts
31 | import { ref } from 'vue'
32 | import { debouncedWatch } from '@/uni_modules/tob-use'
33 |
34 | const source = ref('old')
35 |
36 | const watchChanged = (newValue, oldValue) => console.log(oldValue, '->', newValue)
37 |
38 | debouncedWatch(source, watchChanged, {
39 | deep: true, // 深度同步
40 | immediate: true, // 立即同步,默认为 false
41 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
42 | })
43 | ```
--------------------------------------------------------------------------------
/docs/.vuepress/components/useInterval2.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 | 👉 点击{{ tip }}: {{ counter }}
41 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useVModel/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | ref,
3 | watch,
4 | computed,
5 | getCurrentInstance
6 | } from 'vue'
7 |
8 | /**
9 | * 使用 v-model
10 | */
11 | export const useVModel = (
12 | props,
13 | key = 'modelValue',
14 | emit,
15 | options = {}
16 | ) => {
17 | const {
18 | eventName,
19 | deep = false,
20 | passive = false
21 | } = options
22 |
23 | const vm = getCurrentInstance()
24 |
25 | // 获取 emit
26 | const _emit = emit || vm?.emit || vm?.$emit?.bind(vm)
27 |
28 | // 获取事件名
29 | let event = eventName || `update:${key}`
30 |
31 | if (passive) {
32 | const proxy = ref(props[key])
33 |
34 | watch(
35 | () => props[key],
36 | v => (proxy.value = v)
37 | )
38 |
39 | watch(
40 | proxy,
41 | v => {
42 | if (v !== props[key] || deep) _emit(event, v)
43 | },
44 | {
45 | deep
46 | }
47 | )
48 |
49 | return proxy
50 | } else {
51 | return computed({
52 | get() {
53 | return props[key]
54 | },
55 | set(value) {
56 | _emit(event, value)
57 | }
58 | })
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useTimeoutFn/index.js:
--------------------------------------------------------------------------------
1 | import { ref, unref } from 'vue'
2 | import { tryOnScopeDispose } from '../../component/tryOnScopeDispose'
3 |
4 | /**
5 | * 定时器方法
6 | */
7 | export const useTimeoutFn = (
8 | cb,
9 | interval,
10 | options = {}
11 | ) => {
12 | const {
13 | immediate = true // 立即开始
14 | } = options
15 |
16 | const isPending = ref(false)
17 |
18 | let timer = null
19 |
20 | // 清除定时器
21 | const clear = () => {
22 | if (timer) {
23 | clearTimeout(timer)
24 | timer = null
25 | }
26 | }
27 |
28 | // 暂停
29 | const stop = () => {
30 | isPending.value = false
31 | clear()
32 | }
33 |
34 | // 启动
35 | const start = (...args) => {
36 | clear()
37 | isPending.value = true
38 | timer = setTimeout(() => {
39 | isPending.value = false
40 | timer = null
41 | cb(...args)
42 | }, unref(interval))
43 | }
44 |
45 | // 立即开始
46 | if (immediate) {
47 | isPending.value = true
48 | start()
49 | }
50 |
51 | tryOnScopeDispose(stop)
52 |
53 | return {
54 | isPending,
55 | start,
56 | stop
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/docs/api/utilities/useLastChanged.md:
--------------------------------------------------------------------------------
1 | # useLastChanged
2 |
3 | 获取最后一次更新
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useLastChanged } from '@/uni_modules/tob-use'
12 |
13 | const a = ref(0)
14 |
15 | const lastChanged = useLastChanged(a)
16 |
17 | a.value = 1
18 |
19 | lastChanged.value // 最后一次更新的时间
20 | ```
21 |
22 | ### 初始值
23 |
24 | 大多数情况下你并不需要设置该项 👇
25 |
26 | ```js
27 | import { ref } from 'vue'
28 | import { useLastChanged } from '@/uni_modules/tob-use'
29 |
30 | const a = ref(0)
31 |
32 | const lastChanged = useLastChanged(a, {
33 | initialValue: +Date.now()
34 | })
35 |
36 | lastChanged.value // 初始化时间
37 |
38 | a.value = 1
39 |
40 | lastChanged.value // 最后一次更新的时间
41 | ```
42 |
43 |
44 |
45 | ### Watch 选项
46 |
47 | ```ts
48 | import { ref } from 'vue'
49 | import { useLastChanged } from '@/uni_modules/tob-use'
50 |
51 | const a = ref(0)
52 |
53 | const lastChanged = useLastChanged(a, {
54 | deep: true, // 深度同步
55 | immediate: true, // 立即同步,默认为 false
56 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
57 | })
58 |
59 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/reactifyObject.md:
--------------------------------------------------------------------------------
1 | # reactifyObject
2 |
3 | 对象的响应式转换
4 |
5 | 大白话就是将对象上的方法参数去 `ref` 化 👇
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```js
12 | import { ref } from 'vue'
13 | import { reactifyObject } from '@/uni_modules/tob-use'
14 |
15 | const a = ref(1)
16 |
17 | console.log(a.value) // 需要 .value
18 |
19 | const reactifiedConsole = reactifyObject(console)
20 |
21 | reactifiedConsole.log(a) // 不需要 .value
22 | ```
23 |
24 |
25 |
26 | ### 包含自身属性
27 |
28 | 包含自身属性,包括不可枚举属性但不包括 `Symbol` 值作为名称的属性
29 |
30 | ```ts
31 | import { reactifyObject } from '@/uni_modules/tob-use'
32 |
33 | const reactifiedConsole = reactifyObject(console, {
34 | includeOwnProperties: true // 默认为 true
35 | })
36 | ```
37 |
38 |
39 |
40 | ### 限定范围
41 |
42 | 只允许限定范围内的方法被处理
43 |
44 | ```ts
45 | import { ref } from 'vue'
46 | import { reactifyObject } from '@/uni_modules/tob-use'
47 |
48 | // 只允许 log 被处理
49 | const reactifiedConsole = reactifyObject(console, ['log'])
50 |
51 | const a = ref(1)
52 |
53 | reactifiedConsole.log(a) // 不需要 .value
54 |
55 | reactifiedConsole.warn(a.value) // 需要 .value
56 | ```
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 |
3 | Copyright (c) 2022 markthree
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
8 | to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
13 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
15 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
16 | IN THE SOFTWARE.
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useLastChanged/README.md:
--------------------------------------------------------------------------------
1 | # useLastChanged
2 |
3 | 获取最后一次更新
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { useLastChanged } from '@/uni_modules/tob-use'
12 |
13 | const a = ref(0)
14 |
15 | const lastChanged = useLastChanged(a)
16 |
17 | a.value = 1
18 |
19 | lastChanged.value // 最后一次更新的时间
20 | ```
21 |
22 | ### 初始值
23 |
24 | 大多数情况下你并不需要设置该项 👇
25 |
26 | ```js
27 | import { ref } from 'vue'
28 | import { useLastChanged } from '@/uni_modules/tob-use'
29 |
30 | const a = ref(0)
31 |
32 | const lastChanged = useLastChanged(a, {
33 | initialValue: +Date.now()
34 | })
35 |
36 | lastChanged.value // 初始化时间
37 |
38 | a.value = 1
39 |
40 | lastChanged.value // 最后一次更新的时间
41 | ```
42 |
43 |
44 |
45 | ### Watch 选项
46 |
47 | ```ts
48 | import { ref } from 'vue'
49 | import { useLastChanged } from '@/uni_modules/tob-use'
50 |
51 | const a = ref(0)
52 |
53 | const lastChanged = useLastChanged(a, {
54 | deep: true, // 深度同步
55 | immediate: true, // 立即同步,默认为 false
56 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
57 | })
58 |
59 | ```
--------------------------------------------------------------------------------
/docs/.vuepress/components/eagerComputed3.vue:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 | 点击 👉
37 |
38 |
41 |
复杂计算属性更新次数: {{ complexUpdatedCount }}
42 |
43 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactifyObject/README.md:
--------------------------------------------------------------------------------
1 | # reactifyObject
2 |
3 | 对象的响应式转换
4 |
5 | 大白话就是将对象上的方法参数去 `ref` 化 👇
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```js
12 | import { ref } from 'vue'
13 | import { reactifyObject } from '@/uni_modules/tob-use'
14 |
15 | const a = ref(1)
16 |
17 | console.log(a.value) // 需要 .value
18 |
19 | const reactifiedConsole = reactifyObject(console)
20 |
21 | reactifiedConsole.log(a) // 不需要 .value
22 | ```
23 |
24 |
25 |
26 | ### 包含自身属性
27 |
28 | 包含自身属性,包括不可枚举属性但不包括 `Symbol` 值作为名称的属性
29 |
30 | ```ts
31 | import { reactifyObject } from '@/uni_modules/tob-use'
32 |
33 | const reactifiedConsole = reactifyObject(console, {
34 | includeOwnProperties: true // 默认为 true
35 | })
36 | ```
37 |
38 |
39 |
40 | ### 限定范围
41 |
42 | 只允许限定范围内的方法被处理
43 |
44 | ```ts
45 | import { ref } from 'vue'
46 | import { reactifyObject } from '@/uni_modules/tob-use'
47 |
48 | // 只允许 log 被处理
49 | const reactifiedConsole = reactifyObject(console, ['log'])
50 |
51 | const a = ref(1)
52 |
53 | reactifiedConsole.log(a) // 不需要 .value
54 |
55 | reactifiedConsole.warn(a.value) // 需要 .value
56 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/useCounter.md:
--------------------------------------------------------------------------------
1 | # useCounter
2 |
3 | 计数器
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useCounter } from '@/uni_modules/tob-use'
11 |
12 | const { count, inc, dec, set, reset } = useCounter()
13 |
14 | count.value // 0
15 |
16 | inc() // +1
17 | count.value // 1
18 |
19 | dec() // -1
20 | count.value // 0
21 |
22 | set(100) // 设置
23 | count.value // 100
24 |
25 | reset() // 重置为 0
26 | count.value // 0
27 |
28 | inc(100) // + 100
29 | count.value // 100
30 |
31 | dec(100) // - 100
32 | count.value // 0
33 |
34 | reset(200) // 重置为 200
35 | count.value // 200
36 | ```
37 |
38 | ### 初始值
39 |
40 | ```ts
41 | import { useCounter } from '@/uni_modules/tob-use'
42 |
43 | const { count, inc, dec, set, reset } = useCounter(10)
44 |
45 | count.value // 10
46 |
47 | inc() // +1
48 | count.value // 11
49 |
50 | dec() // -1
51 | count.value // 10
52 |
53 | set(100) // 设置
54 | count.value // 100
55 |
56 | reset() // 重置为 10
57 | count.value // 10
58 |
59 | inc(100) // + 100
60 | count.value // 110
61 |
62 | dec(100) // - 100
63 | count.value // 10
64 |
65 | reset(200) // 重置为 200
66 | count.value // 200
67 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useCycleList/index.js:
--------------------------------------------------------------------------------
1 | import { computed, shallowRef } from 'vue'
2 |
3 | /**
4 | * 环表
5 | */
6 | export const useCycleList = (list, options) => {
7 | // 有初始值则用初始值,无则使用第一个参数
8 | const state = shallowRef(options?.initialValue ?? list[0])
9 |
10 | // 标识
11 | const index = computed({
12 | get() {
13 | let index = options?.getIndexOf
14 | ? options.getIndexOf(state.value, list)
15 | : list.indexOf(state.value)
16 |
17 | if (index < 0) index = options?.fallbackIndex ?? 0
18 |
19 | return index
20 | },
21 | set(v) {
22 | set(v)
23 | }
24 | })
25 |
26 | // 设置
27 | function set(i) {
28 | const { length } = list
29 | const index = ((i % length) + length) % length
30 | const value = list[index]
31 | state.value = value
32 | return value
33 | }
34 |
35 | // 偏移
36 | function shift(delta = 1) {
37 | return set(index.value + delta)
38 | }
39 |
40 | // 下一个
41 | function next(n = 1) {
42 | return shift(n)
43 | }
44 |
45 | // 上一个
46 | function prev(n = 1) {
47 | return shift(-n)
48 | }
49 |
50 | return {
51 | state,
52 | index,
53 | next,
54 | prev
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useCounter/README.md:
--------------------------------------------------------------------------------
1 | # useCounter
2 |
3 | 计数器
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useCounter } from '@/uni_modules/tob-use'
11 |
12 | const { count, inc, dec, set, reset } = useCounter()
13 |
14 | count.value // 0
15 |
16 | inc() // +1
17 | count.value // 1
18 |
19 | dec() // -1
20 | count.value // 0
21 |
22 | set(100) // 设置
23 | count.value // 100
24 |
25 | reset() // 重置为 0
26 | count.value // 0
27 |
28 | inc(100) // + 100
29 | count.value // 100
30 |
31 | dec(100) // - 100
32 | count.value // 0
33 |
34 | reset(200) // 重置为 200
35 | count.value // 200
36 | ```
37 |
38 | ### 初始值
39 |
40 | ```ts
41 | import { useCounter } from '@/uni_modules/tob-use'
42 |
43 | const { count, inc, dec, set, reset } = useCounter(10)
44 |
45 | count.value // 10
46 |
47 | inc() // +1
48 | count.value // 11
49 |
50 | dec() // -1
51 | count.value // 10
52 |
53 | set(100) // 设置
54 | count.value // 100
55 |
56 | reset() // 重置为 10
57 | count.value // 10
58 |
59 | inc(100) // + 100
60 | count.value // 110
61 |
62 | dec(100) // - 100
63 | count.value // 10
64 |
65 | reset(200) // 重置为 200
66 | count.value // 200
67 | ```
--------------------------------------------------------------------------------
/docs/api/animation/useInterval.md:
--------------------------------------------------------------------------------
1 | # useInterval
2 |
3 | 间隔
4 |
5 | ## Usage
6 |
7 |
8 |
9 | ```html
10 |
16 |
17 |
18 | 每 200 毫秒更新: {{ counter }}
19 |
20 | ```
21 |
22 | ### 可控制
23 |
24 |
25 |
26 | ```html
27 |
43 |
44 |
45 | 👉 点击{{ tip }}: {{ counter }}
46 |
47 | ```
48 |
49 |
50 |
51 | ### 立即执行
52 |
53 | ```js
54 | import { useInterval } from '@/uni_modules/tob-use'
55 |
56 | const counter = useInterval(200, {
57 | immediate: false // 立即开启,默认为 true
58 | })
59 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useInterval/README.md:
--------------------------------------------------------------------------------
1 | # useInterval
2 |
3 | 间隔
4 |
5 | ## Usage
6 |
7 |
8 |
9 | ```html
10 |
16 |
17 |
18 | 每 200 毫秒更新: {{ counter }}
19 |
20 | ```
21 |
22 | ### 可控制
23 |
24 |
25 |
26 | ```html
27 |
43 |
44 |
45 | 👉 点击{{ tip }}: {{ counter }}
46 |
47 | ```
48 |
49 |
50 |
51 | ### 立即执行
52 |
53 | ```js
54 | import { useInterval } from '@/uni_modules/tob-use'
55 |
56 | const counter = useInterval(200, {
57 | immediate: false // 立即开启,默认为 true
58 | })
59 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useConfirmDialog/index.js:
--------------------------------------------------------------------------------
1 | import { computed, ref } from 'vue'
2 | import { noop } from '../../shared/base'
3 | import { createEventHook } from '../createEventHook'
4 |
5 | /**
6 | * 确认对话框
7 | */
8 | export const useConfirmDialog = (revealed = ref(false)) => {
9 | const confirmHook = createEventHook()
10 | const cancelHook = createEventHook()
11 | const revealHook = createEventHook()
12 |
13 | let _resolve = noop
14 |
15 | // 显示
16 | const reveal = data => {
17 | revealed.value = true
18 | revealHook.trigger(data)
19 |
20 | return new Promise(resolve => {
21 | _resolve = resolve
22 | })
23 | }
24 |
25 | // 确认
26 | const confirm = data => {
27 | revealed.value = false
28 | confirmHook.trigger(data)
29 |
30 | _resolve({ data, isCanceled: false })
31 | }
32 |
33 | // 取消
34 | const cancel = data => {
35 | revealed.value = false
36 | cancelHook.trigger(data)
37 |
38 | _resolve({ data, isCanceled: true })
39 | }
40 |
41 | return {
42 | reveal,
43 | cancel,
44 | confirm,
45 | onReveal: revealHook.on,
46 | onCancel: cancelHook.on,
47 | onConfirm: confirmHook.on,
48 | isRevealed: computed(() => revealed.value) // 是否显示
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useEventBus/index.js:
--------------------------------------------------------------------------------
1 | import { getCurrentScope } from 'vue'
2 | import { events } from '../../shared/base'
3 |
4 | /**
5 | * 使用事件 bus
6 | */
7 | export const useEventBus = key => {
8 | const scope = getCurrentScope()
9 |
10 | // 注册
11 | const on = listener => {
12 | const listeners = events.get(key) || []
13 | listeners.push(listener)
14 | events.set(key, listeners)
15 |
16 | const _off = () => off(listener)
17 | // auto unsubscribe when scope get disposed
18 | scope?.cleanups.push(_off)
19 | return _off
20 | }
21 |
22 | // 注册一次
23 | const once = listener => {
24 | function _listener(...args) {
25 | off(_listener)
26 | listener(...args)
27 | }
28 | return on(_listener)
29 | }
30 |
31 | // 卸载
32 | const off = listener => {
33 | const listeners = events.get(key)
34 | if (!listeners) return
35 |
36 | const index = listeners.indexOf(listener)
37 | if (index > -1) listeners.splice(index, 1)
38 | if (!listeners.length) events.delete(key)
39 | }
40 |
41 | // 重置
42 | const reset = () => events.delete(key)
43 |
44 | // 触发
45 | const emit = event => {
46 | return events.get(key)?.forEach(v => v(event))
47 | }
48 |
49 | return { on, once, off, emit, reset }
50 | }
51 |
--------------------------------------------------------------------------------
/docs/api/watch/pausableWatch.md:
--------------------------------------------------------------------------------
1 | # pausableWatch
2 |
3 | 可暂停的监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { pausableWatch } from '@/uni_modules/tob-use'
10 |
11 | const source = ref('foo')
12 |
13 | const { stop, pause, resume, isActive } = pausableWatch(
14 | source,
15 | (v) => console.log(v),
16 | )
17 |
18 | const run = async () => {
19 | isActive.value // 监听中,true
20 | source.value = 'bar'
21 | await nextTick() // 输出 bar
22 |
23 | pause() // 暂停
24 | isActive.value // 监听中,false
25 | source.value = 'foobar'
26 | await nextTick() // 啥事都不会发生
27 |
28 | resume() // 恢复
29 | isActive.value // 监听中,true
30 | source.value = 'hello'
31 | await nextTick() // 输出 hello
32 |
33 | stop() // 完全停止监听
34 | }
35 |
36 | run()
37 | ```
38 |
39 |
40 |
41 | ### Watch 选项
42 |
43 | ```ts
44 | import { ref } from 'vue'
45 | import { pausableWatch } from '@/uni_modules/tob-use'
46 |
47 | const source = ref('foo')
48 | const callback = (v) => console.log(`更新 ${v}!`)
49 |
50 | pausableWatch(
51 | source,
52 | callback,
53 | {
54 | deep: true, // 深度同步
55 | immediate: true, // 立即同步,默认为 false
56 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
57 | }
58 | )
59 | ```
--------------------------------------------------------------------------------
/docs/api/component/useVModels.md:
--------------------------------------------------------------------------------
1 | # useVModels
2 |
3 | 使用多个的 v-model
4 |
5 | 大多数情况下,可能你只需要使用 [useVModel](/api/component/useVModel)
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```html
12 |
33 | ```
34 |
35 |
36 |
37 | ### 选项
38 |
39 | ```html
40 |
59 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/pausableWatch/README.md:
--------------------------------------------------------------------------------
1 | # pausableWatch
2 |
3 | 可暂停的监听
4 |
5 | ## Usage
6 |
7 | ```js
8 | import { ref } from 'vue'
9 | import { pausableWatch } from '@/uni_modules/tob-use'
10 |
11 | const source = ref('foo')
12 |
13 | const { stop, pause, resume, isActive } = pausableWatch(
14 | source,
15 | (v) => console.log(v),
16 | )
17 |
18 | const run = async () => {
19 | isActive.value // 监听中,true
20 | source.value = 'bar'
21 | await nextTick() // 输出 bar
22 |
23 | pause() // 暂停
24 | isActive.value // 监听中,false
25 | source.value = 'foobar'
26 | await nextTick() // 啥事都不会发生
27 |
28 | resume() // 恢复
29 | isActive.value // 监听中,true
30 | source.value = 'hello'
31 | await nextTick() // 输出 hello
32 |
33 | stop() // 完全停止监听
34 | }
35 |
36 | run()
37 | ```
38 |
39 |
40 |
41 | ### Watch 选项
42 |
43 | ```ts
44 | import { ref } from 'vue'
45 | import { pausableWatch } from '@/uni_modules/tob-use'
46 |
47 | const source = ref('foo')
48 | const callback = (v) => console.log(`更新 ${v}!`)
49 |
50 | pausableWatch(
51 | source,
52 | callback,
53 | {
54 | deep: true, // 深度同步
55 | immediate: true, // 立即同步,默认为 false
56 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
57 | }
58 | )
59 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useVModels/README.md:
--------------------------------------------------------------------------------
1 | # useVModels
2 |
3 | 使用多个的 v-model
4 |
5 | 大多数情况下,可能你只需要使用 [useVModel](/api/component/useVModel)
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```html
12 |
33 | ```
34 |
35 |
36 |
37 | ### 选项
38 |
39 | ```html
40 |
59 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useMemoize/index.js:
--------------------------------------------------------------------------------
1 | import { reactive } from 'vue'
2 |
3 | /**
4 | * 使用备份
5 | */
6 | export const useMemoize = (resolver, options) => {
7 | const initCache = () => {
8 | if (options?.cache) {
9 | return reactive(options.cache)
10 | }
11 |
12 | return reactive(new Map())
13 | }
14 | const cache = initCache()
15 |
16 | const generateKey = (...args) =>
17 | options?.getKey
18 | ? options.getKey(...args)
19 | : JSON.stringify(args)
20 |
21 | // 加载数据(私有)
22 | const _loadData = (key, ...args) => {
23 | cache.set(key, resolver(...args))
24 | return cache.get(key)
25 | }
26 | // 加载数据
27 | const loadData = (...args) =>
28 | _loadData(generateKey(...args), ...args)
29 |
30 | // 删除数据
31 | const deleteData = (...args) => {
32 | cache.delete(generateKey(...args))
33 | }
34 |
35 | // 清空数据
36 | const clearData = () => cache.clear()
37 |
38 | // 记忆函数 (有缓存时走缓存)
39 | const memoized = (...args) => {
40 | const key = generateKey(...args)
41 | if (cache.has(key)) return cache.get(key)
42 | return _loadData(key, ...args)
43 | }
44 | memoized.load = loadData
45 | memoized.delete = deleteData
46 | memoized.clear = clearData
47 | memoized.generateKey = generateKey
48 | memoized.cache = cache
49 |
50 | return memoized
51 | }
52 |
--------------------------------------------------------------------------------
/docs/api/utilities/reactify.md:
--------------------------------------------------------------------------------
1 | # reactify
2 |
3 | 将普通函数转换为响应式函数
4 |
5 | 大白话就是对函数参数去 `ref` 化 👇
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```ts
12 | import { ref } from 'vue'
13 | import { reactify } from '@/uni_modules/tob-use'
14 |
15 | const count = ref(1)
16 |
17 | // reactify 注册一个回调,返回一个工厂函数
18 | const createDouble = reactify(v => {
19 | return v * 2 // 这里的 v 就是后边 count.value
20 | })
21 |
22 | // 返回一个计算属性
23 | const double = createDouble(count)
24 |
25 | console.log(double.value) // 2
26 |
27 | count.value = 2
28 |
29 | console.log(double.value) // 4
30 | ```
31 |
32 |
33 |
34 | ### 对比
35 |
36 | 对比原生计算属性 👇
37 |
38 | ```ts
39 | import { ref, computed } from 'vue'
40 |
41 | const a = ref(1)
42 | const b = 2
43 | const c = ref(3)
44 |
45 | const sum = computed(() => {
46 | // 需要考虑 .value
47 | return a.value + b + c.value
48 | })
49 |
50 | console.log(sum.value) // 6
51 | ```
52 |
53 | 用 `reactify` 👇
54 |
55 | ```ts
56 | import { ref } from 'vue'
57 | import { reactify } from '@/uni_modules/tob-use'
58 |
59 | const createSum = reactify((a, b, c) => {
60 | // 不需要考虑 .value
61 | return a + b + c
62 | })
63 |
64 | const a = ref(1)
65 | const b = 2
66 | const c = ref(3)
67 |
68 | const sum = createSum(a, b, c)
69 |
70 | console.log(sum.value)
71 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/useAsyncQueue.md:
--------------------------------------------------------------------------------
1 | # useAsyncQueue
2 |
3 | 使用异步队列
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useAsyncQueue } from '@/uni_modules/tob-use'
11 |
12 | const p1 = () => {
13 | return new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(1000)
16 | }, 10)
17 | })
18 | }
19 |
20 | // result 是上一个任务的结果
21 | const p2 = result => {
22 | return new Promise((resolve) => {
23 | setTimeout(() => {
24 | resolve(1000 + result)
25 | }, 20)
26 | })
27 | }
28 |
29 | const { activeIndex, result } = useAsyncQueue([p1, p2])
30 |
31 |
32 | setTimeout(() => {
33 | result // 结果
34 | activeIndex.value // 当前执行到的任务 index
35 | }, 1000)
36 | ```
37 |
38 |
39 |
40 | ### 打断
41 |
42 | ```ts
43 | import { useAsyncQueue } from '@/uni_modules/tob-use'
44 |
45 | const { activeIndex, result } = useAsyncQueue([
46 | // ... 省略异步任务
47 | ], {
48 | interrupt: true // 允许失败时打断,默认为 true
49 | })
50 | ```
51 |
52 |
53 |
54 | ### 回调
55 |
56 | ```ts
57 | import { useAsyncQueue } from '@/uni_modules/tob-use'
58 |
59 | const { activeIndex, result } = useAsyncQueue([
60 | // ... 省略异步任务
61 | ], {
62 | // 出错时回调
63 | onError() {
64 |
65 | },
66 | // 成功时回调
67 | onFinished() {
68 |
69 | }
70 | })
71 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/reactify/README.md:
--------------------------------------------------------------------------------
1 | # reactify
2 |
3 | 将普通函数转换为响应式函数
4 |
5 | 大白话就是对函数参数去 `ref` 化 👇
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```ts
12 | import { ref } from 'vue'
13 | import { reactify } from '@/uni_modules/tob-use'
14 |
15 | const count = ref(1)
16 |
17 | // reactify 注册一个回调,返回一个工厂函数
18 | const createDouble = reactify(v => {
19 | return v * 2 // 这里的 v 就是后边 count.value
20 | })
21 |
22 | // 返回一个计算属性
23 | const double = createDouble(count)
24 |
25 | console.log(double.value) // 2
26 |
27 | count.value = 2
28 |
29 | console.log(double.value) // 4
30 | ```
31 |
32 |
33 |
34 | ### 对比
35 |
36 | 对比原生计算属性 👇
37 |
38 | ```ts
39 | import { ref, computed } from 'vue'
40 |
41 | const a = ref(1)
42 | const b = 2
43 | const c = ref(3)
44 |
45 | const sum = computed(() => {
46 | // 需要考虑 .value
47 | return a.value + b + c.value
48 | })
49 |
50 | console.log(sum.value) // 6
51 | ```
52 |
53 | 用 `reactify` 👇
54 |
55 | ```ts
56 | import { ref } from 'vue'
57 | import { reactify } from '@/uni_modules/tob-use'
58 |
59 | const createSum = reactify((a, b, c) => {
60 | // 不需要考虑 .value
61 | return a + b + c
62 | })
63 |
64 | const a = ref(1)
65 | const b = 2
66 | const c = ref(3)
67 |
68 | const sum = createSum(a, b, c)
69 |
70 | console.log(sum.value)
71 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useAsyncQueue/README.md:
--------------------------------------------------------------------------------
1 | # useAsyncQueue
2 |
3 | 使用异步队列
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useAsyncQueue } from '@/uni_modules/tob-use'
11 |
12 | const p1 = () => {
13 | return new Promise((resolve) => {
14 | setTimeout(() => {
15 | resolve(1000)
16 | }, 10)
17 | })
18 | }
19 |
20 | // result 是上一个任务的结果
21 | const p2 = result => {
22 | return new Promise((resolve) => {
23 | setTimeout(() => {
24 | resolve(1000 + result)
25 | }, 20)
26 | })
27 | }
28 |
29 | const { activeIndex, result } = useAsyncQueue([p1, p2])
30 |
31 |
32 | setTimeout(() => {
33 | result // 结果
34 | activeIndex.value // 当前执行到的任务 index
35 | }, 1000)
36 | ```
37 |
38 |
39 |
40 | ### 打断
41 |
42 | ```ts
43 | import { useAsyncQueue } from '@/uni_modules/tob-use'
44 |
45 | const { activeIndex, result } = useAsyncQueue([
46 | // ... 省略异步任务
47 | ], {
48 | interrupt: true // 允许失败时打断,默认为 true
49 | })
50 | ```
51 |
52 |
53 |
54 | ### 回调
55 |
56 | ```ts
57 | import { useAsyncQueue } from '@/uni_modules/tob-use'
58 |
59 | const { activeIndex, result } = useAsyncQueue([
60 | // ... 省略异步任务
61 | ], {
62 | // 出错时回调
63 | onError() {
64 |
65 | },
66 | // 成功时回调
67 | onFinished() {
68 |
69 | }
70 | })
71 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/useOffsetPagination.md:
--------------------------------------------------------------------------------
1 | # useOffsetPagination
2 |
3 | 偏移分页
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useOffsetPagination } from '@/uni_modules/tob-use'
11 |
12 | const result = useOffsetPagination({
13 | page: 1, // 初始当前第几页,默认为 1
14 | pageSize: 20, // 每页元素数量,默认为 10
15 | total: 100 // 总元素数量,默认为 Infinity 无限
16 | })
17 |
18 | result.pageCount.value // 总页数,计算属性
19 |
20 | result.currentPage.value // 当前第几页,计算属性
21 |
22 | result.isFirstPage.value // 是否是第一页,计算属性
23 | result.isLastPage.value // 是否是最后一页,计算属性
24 |
25 | result.currentPageSize.value // 当前每页元素数量,计算属性
26 |
27 | result.prev() // 上一页,触发 result.currentPage.value++
28 | result.next() // 下一页,触发 result.currentPage.value--
29 | ```
30 |
31 |
32 |
33 | ### 回调
34 |
35 | ```ts
36 | import { useOffsetPagination } from '@/uni_modules/tob-use'
37 |
38 | const result = useOffsetPagination({
39 | // 省略其他配置 ...
40 | // 总页数 result.pageCount 变化时触发
41 | onPageCountChange(result) {
42 | result // 上一次的结果,不过是一个 reactive
43 | },
44 | // 当前第几页 result.currentPage 变更时触发
45 | onPageChange(result) {
46 | result // 上一次的结果,不过是一个 reactive
47 | },
48 | // 当前每页元素数量 result.currentPageSize 变化时触发
49 | onPageSizeChange(result) {
50 | result // 上一次的结果,不过是一个 reactive
51 | }
52 | })
53 | ```
--------------------------------------------------------------------------------
/docs/api/watch/ignorableWatch.md:
--------------------------------------------------------------------------------
1 | # ignorableWatch
2 |
3 | 忽略型监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref, nextTick } from 'vue'
11 | import { ignorableWatch } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('foo')
14 |
15 | const { stop, ignoreUpdates, ignorePrevAsyncUpdates } = ignorableWatch(
16 | source,
17 | (v) => console.log(`更新 ${v}!`),
18 | )
19 |
20 | const run = async () => {
21 | source.value = 'bar'
22 | await nextTick() // 输出 '更新 bar'
23 |
24 | ignoreUpdates(() => {
25 | source.value = 'foobar' // 忽略了此处更新,不会触发回调
26 | })
27 | await nextTick() // 无事发生
28 |
29 | source.value = 'good'
30 | ignorePrevAsyncUpdates() // 忽略上一次仍未处理的的更新,所以不会触发回调
31 | await nextTick() // 无事发生
32 |
33 | stop() // 暂停监听
34 |
35 | source.value = 'jack' // 不会触发回调,因为已经暂停了
36 | }
37 |
38 | run()
39 | ```
40 |
41 |
42 |
43 | ### Watch 选项
44 |
45 | ```ts
46 | import { ref } from 'vue'
47 | import { ignorableWatch } from '@/uni_modules/tob-use'
48 |
49 | const source = ref('foo')
50 | const callback = (v) => console.log(`更新 ${v}!`)
51 |
52 | ignorableWatch(
53 | source,
54 | callback,
55 | {
56 | deep: true, // 深度同步
57 | immediate: true, // 立即同步,默认为 false
58 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
59 | }
60 | )
61 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/syncRef.md:
--------------------------------------------------------------------------------
1 | # syncRef
2 |
3 | 保持目标 ref 跟源同步
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { syncRef } from '@/uni_modules/tob-use'
12 |
13 | const source = ref(1)
14 | const target = ref(2)
15 |
16 | // 保持目标 target 跟源 source 同步,并返回 stop 暂停同步函数
17 | const stop = syncRef(source, target)
18 |
19 | target.value // 1
20 |
21 | source.value = 10
22 |
23 | target.value // 10
24 |
25 | stop() // 暂停同步
26 |
27 | source.value = 100
28 |
29 | target.value // 仍然是 10
30 | ```
31 |
32 | ### 多个
33 |
34 | ```ts
35 | import { ref } from 'vue'
36 | import { syncRef } from '@/uni_modules/tob-use'
37 |
38 | const a = ref(1)
39 | const b = ref(2)
40 | const c = ref(2)
41 |
42 | // 保持目标 b, c 跟源 a 同步,并返回 stop 暂停函数
43 | const stop = syncRef(a, [b, c])
44 |
45 | b.value // 1
46 | c.value // 1
47 |
48 | a.value = 2
49 |
50 | b.value // 2
51 | c.value // 2
52 | ```
53 |
54 | ### 配置
55 |
56 | `syncRef` 第三个参数,支持 `watch` 配置
57 |
58 | ```ts
59 | import { ref } from 'vue'
60 | import { syncRef } from '@/uni_modules/tob-use'
61 |
62 | const source = ref(1)
63 | const target = ref(2)
64 |
65 | const stop = syncRef(source, target, {
66 | deep: false, // 深度同步,默认为 false
67 | immediate: true, // 立即同步,默认为 true
68 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 sync
69 | })
70 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useOffsetPagination/README.md:
--------------------------------------------------------------------------------
1 | # useOffsetPagination
2 |
3 | 偏移分页
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { useOffsetPagination } from '@/uni_modules/tob-use'
11 |
12 | const result = useOffsetPagination({
13 | page: 1, // 初始当前第几页,默认为 1
14 | pageSize: 20, // 每页元素数量,默认为 10
15 | total: 100 // 总元素数量,默认为 Infinity 无限
16 | })
17 |
18 | result.pageCount.value // 总页数,计算属性
19 |
20 | result.currentPage.value // 当前第几页,计算属性
21 |
22 | result.isFirstPage.value // 是否是第一页,计算属性
23 | result.isLastPage.value // 是否是最后一页,计算属性
24 |
25 | result.currentPageSize.value // 当前每页元素数量,计算属性
26 |
27 | result.prev() // 上一页,触发 result.currentPage.value++
28 | result.next() // 下一页,触发 result.currentPage.value--
29 | ```
30 |
31 |
32 |
33 | ### 回调
34 |
35 | ```ts
36 | import { useOffsetPagination } from '@/uni_modules/tob-use'
37 |
38 | const result = useOffsetPagination({
39 | // 省略其他配置 ...
40 | // 总页数 result.pageCount 变化时触发
41 | onPageCountChange(result) {
42 | result // 上一次的结果,不过是一个 reactive
43 | },
44 | // 当前第几页 result.currentPage 变更时触发
45 | onPageChange(result) {
46 | result // 上一次的结果,不过是一个 reactive
47 | },
48 | // 当前每页元素数量 result.currentPageSize 变化时触发
49 | onPageSizeChange(result) {
50 | result // 上一次的结果,不过是一个 reactive
51 | }
52 | })
53 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/animation/useIntervalFn/index.js:
--------------------------------------------------------------------------------
1 | import { isRef, ref, unref, watch } from 'vue'
2 | import { tryOnScopeDispose } from '../../component/tryOnScopeDispose'
3 |
4 | /**
5 | * 间隔循环函数
6 | */
7 | export const useIntervalFn = (
8 | cb,
9 | interval = 1000,
10 | options = {}
11 | ) => {
12 | const {
13 | immediate = true, // 立即开启间隔函数
14 | immediateCallback = false // 立即触发间隔函数
15 | } = options
16 |
17 | let timer = null
18 | const isActive = ref(false) // 是否处于开启间隔状态
19 |
20 | // 清除
21 | const clean = () => {
22 | if (timer) {
23 | clearInterval(timer)
24 | timer = null
25 | }
26 | }
27 |
28 | // 暂停
29 | const pause = () => {
30 | isActive.value = false
31 | clean()
32 | }
33 |
34 | // 恢复
35 | const resume = () => {
36 | if (interval <= 0) return
37 | isActive.value = true
38 | if (immediateCallback) cb()
39 | clean()
40 | timer = setInterval(cb, unref(interval))
41 | }
42 |
43 | // 立即触发间隔函数
44 | if (immediate) resume()
45 |
46 | // interval 为 ref 时,可动态设置间隔大小
47 | if (isRef(interval)) {
48 | const stopWatch = watch(interval, () => {
49 | if (immediate) resume()
50 | })
51 | // 尝试获取区域内副作用暂停
52 | tryOnScopeDispose(stopWatch)
53 | }
54 |
55 | //尝试获取区域内副作用暂停
56 | tryOnScopeDispose(pause)
57 |
58 | return {
59 | isActive,
60 | pause,
61 | resume
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/syncRef/README.md:
--------------------------------------------------------------------------------
1 | # syncRef
2 |
3 | 保持目标 ref 跟源同步
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref } from 'vue'
11 | import { syncRef } from '@/uni_modules/tob-use'
12 |
13 | const source = ref(1)
14 | const target = ref(2)
15 |
16 | // 保持目标 target 跟源 source 同步,并返回 stop 暂停同步函数
17 | const stop = syncRef(source, target)
18 |
19 | target.value // 1
20 |
21 | source.value = 10
22 |
23 | target.value // 10
24 |
25 | stop() // 暂停同步
26 |
27 | source.value = 100
28 |
29 | target.value // 仍然是 10
30 | ```
31 |
32 | ### 多个
33 |
34 | ```ts
35 | import { ref } from 'vue'
36 | import { syncRef } from '@/uni_modules/tob-use'
37 |
38 | const a = ref(1)
39 | const b = ref(2)
40 | const c = ref(2)
41 |
42 | // 保持目标 b, c 跟源 a 同步,并返回 stop 暂停函数
43 | const stop = syncRef(a, [b, c])
44 |
45 | b.value // 1
46 | c.value // 1
47 |
48 | a.value = 2
49 |
50 | b.value // 2
51 | c.value // 2
52 | ```
53 |
54 | ### 配置
55 |
56 | `syncRef` 第三个参数,支持 `watch` 配置
57 |
58 | ```ts
59 | import { ref } from 'vue'
60 | import { syncRef } from '@/uni_modules/tob-use'
61 |
62 | const source = ref(1)
63 | const target = ref(2)
64 |
65 | const stop = syncRef(source, target, {
66 | deep: false, // 深度同步,默认为 false
67 | immediate: true, // 立即同步,默认为 true
68 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 sync
69 | })
70 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/ignorableWatch/README.md:
--------------------------------------------------------------------------------
1 | # ignorableWatch
2 |
3 | 忽略型监听
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { ref, nextTick } from 'vue'
11 | import { ignorableWatch } from '@/uni_modules/tob-use'
12 |
13 | const source = ref('foo')
14 |
15 | const { stop, ignoreUpdates, ignorePrevAsyncUpdates } = ignorableWatch(
16 | source,
17 | (v) => console.log(`更新 ${v}!`),
18 | )
19 |
20 | const run = async () => {
21 | source.value = 'bar'
22 | await nextTick() // 输出 '更新 bar'
23 |
24 | ignoreUpdates(() => {
25 | source.value = 'foobar' // 忽略了此处更新,不会触发回调
26 | })
27 | await nextTick() // 无事发生
28 |
29 | source.value = 'good'
30 | ignorePrevAsyncUpdates() // 忽略上一次仍未处理的的更新,所以不会触发回调
31 | await nextTick() // 无事发生
32 |
33 | stop() // 暂停监听
34 |
35 | source.value = 'jack' // 不会触发回调,因为已经暂停了
36 | }
37 |
38 | run()
39 | ```
40 |
41 |
42 |
43 | ### Watch 选项
44 |
45 | ```ts
46 | import { ref } from 'vue'
47 | import { ignorableWatch } from '@/uni_modules/tob-use'
48 |
49 | const source = ref('foo')
50 | const callback = (v) => console.log(`更新 ${v}!`)
51 |
52 | ignorableWatch(
53 | source,
54 | callback,
55 | {
56 | deep: true, // 深度同步
57 | immediate: true, // 立即同步,默认为 false
58 | flush: 'sync', // 同步时机,支持 pre,post,sync,默认为 pre
59 | }
60 | )
61 | ```
--------------------------------------------------------------------------------
/docs/guide/index.md:
--------------------------------------------------------------------------------
1 | # 介绍
2 |
3 | ## 是什么?
4 |
5 | **tob-use** 是由 **composition-api** 构建的 **use** 库,主要面向 **vue3** 下的 **uniapp** 高效开发。
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## 为什么?
13 |
14 | 为什么要做这个 **use 库** 呢?
15 |
16 | 1. 为了使用强大的 `composition-api`
17 | 2. 为了让 `uniapp` 的开发更高效,节省时间做更多其他的事情
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## 特点
25 |
26 | 1. 功能丰富
27 | - `60+` 的功能供你选择
28 | 2. 按需加载
29 | - 让你的应用体积更小
30 | 3. 灵活可配置
31 | - 可配置的事件过滤器
32 | 4. 支持多端
33 | - 支持 `app`,`h5` 和小程序
34 | 5. composition
35 | - 完全由 `composition-api` 构建
36 | 6. vue3
37 | - 支持最现代化的 `vue3` 版本
38 |
39 |
40 |
41 |
42 |
43 |
44 | ## 启发
45 |
46 | 该 `use` 库 受 [vueuse](https://vueuse.org/) 启发,同时该 `use` 库绝大部分 `api` 来自其不需要依赖 `web` 环境的部分。
47 |
48 | 如果你希望在 `vue3` 下为构建纯 `web` 项目提高开发效率,节省时间,那么推荐你使用 👉 [vueuse](https://vueuse.org/)。
49 |
50 |
51 |
52 |
53 |
54 | ## 组织
55 |
56 | 欢迎关注 **帝莎编程**
57 |
58 | - [官网](http://dishaxy.dishait.cn/)
59 | - [Gitee](https://gitee.com/dishait)
60 | - [Github](https://github.com/dishait)
61 | - [网易云课堂](https://study.163.com/provider/480000001892585/index.htm?share=2&shareId=480000001892585)
62 |
63 |
64 |
65 |
66 |
67 | ## 仓库
68 |
69 | - [Github](https://github.com/dishait/tob-use)
70 | - [Gitee](https://gitee.com/dishait/tob-use)
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tob-use
2 |
3 | **tob-use** 是由 **composition-api** 构建的 **use** 库,主要面向 **vue3** 下的 **uniapp** 高效开发
4 |
5 |
6 |
7 |
8 | ## 特点 🐳
9 |
10 | 1. 功能丰富
11 | - `60+` 的功能供你选择
12 | 2. 按需加载
13 | - 让你的应用体积更小
14 | 3. 灵活可配置
15 | - 可配置的事件过滤器
16 | 4. 支持多端
17 | - 支持 `app`,`h5` 和小程序
18 | 5. composition
19 | - 完全由 `composition-api` 构建
20 | 6. vue3
21 | - 支持最现代化的 `vue3` 版本
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## [在线文档](https://tob-use.netlify.app/) 🐇
29 |
30 | 点击跳转 👉 [tob-use](https://tob-use.netlify.app/)
31 |
32 |
33 |
34 |
35 |
36 | ## 动机 🦕
37 |
38 | 为什么要做这个 **use 库** 呢?
39 |
40 | 1. 为了使用强大的 `composition-api`
41 | 2. 为了让 `uniapp` 的开发更高效,节省时间做更多其他的事情
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | ## 启发 🦖
50 |
51 | 该 `use` 库 受 [vueuse](https://vueuse.org/) 启发,同时该 `use` 库绝大部分 `api` 来自其不需要依赖 `web` 环境的部分。
52 |
53 | 如果你希望在 `vue3` 下为构建纯 `web` 项目提高开发效率,节省时间,那么推荐你使用 👉 [vueuse](https://vueuse.org/)。
54 |
55 |
56 |
57 |
58 | ## 组织 🦔
59 |
60 | 欢迎关注 **帝莎编程**
61 | - [官网](http://dishaxy.dishait.cn/)
62 | - [Gitee](https://gitee.com/dishait)
63 |
64 | - [Github](https://github.com/dishait)
65 |
66 | - [网易云课堂](https://study.163.com/provider/480000001892585/index.htm?share=2&shareId=480000001892585)
67 |
68 |
69 |
70 |
71 | ## 仓库 📦
72 |
73 | - [Github](https://github.com/dishait/tob-use)
74 | - [Gitee](https://gitee.com/dishait/tob-use)
75 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/readme.md:
--------------------------------------------------------------------------------
1 | # tob-use
2 |
3 | **tob-use** 是由 **composition-api** 构建的 **use** 库,主要面向 **vue3** 下的 **uniapp** 高效开发
4 |
5 |
6 |
7 |
8 | ## 特点 🐳
9 |
10 | 1. 功能丰富
11 | - `60+` 的功能供你选择
12 | 2. 按需加载
13 | - 让你的应用体积更小
14 | 3. 灵活可配置
15 | - 可配置的事件过滤器
16 | 4. 支持多端
17 | - 支持 `app`,`h5` 和小程序
18 | 5. composition
19 | - 完全由 `composition-api` 构建
20 | 6. vue3
21 | - 支持最现代化的 `vue3` 版本
22 |
23 |
24 |
25 |
26 |
27 |
28 | ## [在线文档](https://tob-use.netlify.app/) 🐇
29 |
30 | 点击跳转 👉 [tob-use](https://tob-use.netlify.app/)
31 |
32 |
33 |
34 |
35 |
36 | ## 动机 🦕
37 |
38 | 为什么要做这个 **use 库** 呢?
39 |
40 | 1. 为了使用强大的 `composition-api`
41 | 2. 为了让 `uniapp` 的开发更高效,节省时间做更多其他的事情
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | ## 启发 🦖
50 |
51 | 该 `use` 库 受 [vueuse](https://vueuse.org/) 启发,同时该 `use` 库绝大部分 `api` 来自其不需要依赖 `web` 环境的部分。
52 |
53 | 如果你希望在 `vue3` 下为构建纯 `web` 项目提高开发效率,节省时间,那么推荐你使用 👉 [vueuse](https://vueuse.org/)。
54 |
55 |
56 |
57 |
58 | ## 组织 🦔
59 |
60 | 欢迎关注 **帝莎编程**
61 | - [官网](http://dishaxy.dishait.cn/)
62 | - [Gitee](https://gitee.com/dishait)
63 |
64 | - [Github](https://github.com/dishait)
65 |
66 | - [网易云课堂](https://study.163.com/provider/480000001892585/index.htm?share=2&shareId=480000001892585)
67 |
68 |
69 |
70 |
71 | ## 仓库 📦
72 |
73 | - [Github](https://github.com/dishait/tob-use)
74 | - [Gitee](https://gitee.com/dishait/tob-use)
75 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/controlledRef/index.js:
--------------------------------------------------------------------------------
1 | import { customRef } from 'vue'
2 | import { extendRef } from '../extendRef'
3 |
4 | /**
5 | * 受控型 ref
6 | */
7 | export const controlledRef = (initial, options = {}) => {
8 | let source = initial
9 | let track
10 | let trigger
11 |
12 | const ref = customRef((_track, _trigger) => {
13 | track = _track
14 | trigger = _trigger
15 |
16 | return {
17 | get() {
18 | return get()
19 | },
20 | set(v) {
21 | set(v)
22 | }
23 | }
24 | })
25 |
26 | // 获取
27 | const get = (tracking = true) => {
28 | if (tracking) {
29 | track()
30 | }
31 | return source
32 | }
33 |
34 | // 设置
35 | const set = (value, triggering = true) => {
36 | const shouldUpdate = value !== source
37 | if (!shouldUpdate) return
38 |
39 | const old = source
40 | // 调用变更之前的 hook
41 | if (options.onBeforeChange?.(value, old) === false) {
42 | return
43 | }
44 |
45 | source = value
46 |
47 | // 调用变更之后的 hook
48 | options.onChanged?.(value, old)
49 |
50 | if (triggering) {
51 | trigger()
52 | }
53 | }
54 |
55 | // 不触发收集的获取
56 | const untrackedGet = () => get(false)
57 |
58 | // 单纯的设置,单不触发副作用
59 | const silentSet = v => set(v, false)
60 |
61 | // 偷窥,untrackedGet 的别名
62 | const peek = () => get(false)
63 |
64 | // 轻放,silentSet 的别名
65 | const lay = v => set(v, false)
66 |
67 | // 扩展原有的 ref
68 | return extendRef(
69 | ref,
70 | {
71 | get,
72 | set,
73 | untrackedGet,
74 | silentSet,
75 | peek,
76 | lay
77 | },
78 | { enumerable: true }
79 | )
80 | }
81 |
--------------------------------------------------------------------------------
/docs/api/utilities/createEventHook.md:
--------------------------------------------------------------------------------
1 | # createEventHook
2 |
3 | 创建事件 hook
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```ts
10 | import { createEventHook } from '@/uni_modules/tob-use'
11 |
12 | const event = createEventHook()
13 |
14 | // on 可以注册回调
15 | event.on(v => {
16 | console.log(v)
17 | })
18 |
19 | event.trigger(0) // 触发 on 注册的回调,打印 0
20 |
21 | // 再注册一个
22 | event.on(v => {
23 | console.log(v + 1)
24 | })
25 |
26 | event.trigger(1) // 触发所有 on 注册的回调,打印 1,2
27 |
28 | // 可解构获取卸载函数
29 | const { off } = event.on(v => {
30 | console.log('触发了')
31 | })
32 |
33 | off() // 卸载刚注册的回调
34 |
35 | event.trigger(1) // 打印 1,2,但不会打印 '触发了',因为刚刚被卸载了
36 | ```
37 |
38 |
39 |
40 | ### 封装请求
41 |
42 | ```js
43 | import { createEventHook } from '@/uni_modules/tob-use'
44 |
45 | /**
46 | * 封装请求
47 | */
48 | const useUserInfo = () => {
49 | const failEvent = createEventHook()
50 | const successEvent = createEventHook()
51 | uni.request({
52 | url: 'https://www.example.com/request', // 虚拟请求地址
53 | fail(err) {
54 | failEvent.trigger(err) // 失败时触发
55 | },
56 | success(res) {
57 | successEvent.trigger(res) // 成功时触发
58 | },
59 | })
60 |
61 | return {
62 | onFail: failEvent.on, // 失败监听
63 | onSuccess: successEvent.on // 成功监听
64 | }
65 | }
66 |
67 | /**
68 | * 使用时
69 | */
70 | const { onFail, onSuccess } = useUserInfo()
71 |
72 | // 注册失败回调,失败时将被触发
73 | onFail(err => {
74 | console.log(err)
75 | })
76 |
77 | // 注册成功回调,成功时将被触发
78 | onSuccess(res => {
79 | console.log(res)
80 | })
81 | ```
82 |
83 |
84 |
--------------------------------------------------------------------------------
/docs/.vuepress/theme/shared.ts:
--------------------------------------------------------------------------------
1 | import { sync } from 'fast-glob'
2 | import { dirname, basename } from 'path'
3 | import { ensureLinkSync } from 'fs-extra'
4 | import { utimesSync, openSync, closeSync } from 'fs'
5 |
6 | export const _DEV_ = process.env.NODE_ENV === 'development'
7 |
8 | export const touch = (path: string) => {
9 | const time = new Date()
10 | try {
11 | utimesSync(path, time, time)
12 | } catch (error) {
13 | closeSync(openSync(path, 'w'))
14 | }
15 | }
16 |
17 | export const showName = (path: string) => {
18 | return basename(dirname(path))
19 | }
20 |
21 | export const showType = (path: string) => {
22 | return basename(dirname(dirname(path)))
23 | }
24 |
25 | export const useDest = (path: string) => {
26 | const name = showName(path)
27 | // 跳过根目录下的文件
28 | const skip = name === 'tob-use'
29 | if (skip) {
30 | return { skip: true }
31 | }
32 | const type = showType(path)
33 | const dest = `./docs/api/${type}/${name}.md`
34 |
35 | return { dest, type, name }
36 | }
37 |
38 | interface Routes {
39 | [k: string]: string[]
40 | }
41 |
42 | // 生成 api 的路由表
43 | export const generateApiRoutes = (): Routes => {
44 | const srcPaths = sync(`./uni_modules/tob-use/**/*.md`)
45 | const routes: Routes = {}
46 | srcPaths.forEach(src => {
47 | const { dest, type, skip, name } = useDest(src)
48 |
49 | if (skip) {
50 | return
51 | }
52 |
53 | // 补充硬链接的更新
54 | _DEV_ && ensureLinkSync(src, dest)
55 |
56 | let sidebar = routes[type]
57 | if (!sidebar) {
58 | sidebar = routes[type] = []
59 | }
60 | sidebar.push(`/api/${type}/${name}.md`)
61 | })
62 | return routes
63 | }
64 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/createEventHook/README.md:
--------------------------------------------------------------------------------
1 | # createEventHook
2 |
3 | 创建事件 hook
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```ts
10 | import { createEventHook } from '@/uni_modules/tob-use'
11 |
12 | const event = createEventHook()
13 |
14 | // on 可以注册回调
15 | event.on(v => {
16 | console.log(v)
17 | })
18 |
19 | event.trigger(0) // 触发 on 注册的回调,打印 0
20 |
21 | // 再注册一个
22 | event.on(v => {
23 | console.log(v + 1)
24 | })
25 |
26 | event.trigger(1) // 触发所有 on 注册的回调,打印 1,2
27 |
28 | // 可解构获取卸载函数
29 | const { off } = event.on(v => {
30 | console.log('触发了')
31 | })
32 |
33 | off() // 卸载刚注册的回调
34 |
35 | event.trigger(1) // 打印 1,2,但不会打印 '触发了',因为刚刚被卸载了
36 | ```
37 |
38 |
39 |
40 | ### 封装请求
41 |
42 | ```js
43 | import { createEventHook } from '@/uni_modules/tob-use'
44 |
45 | /**
46 | * 封装请求
47 | */
48 | const useUserInfo = () => {
49 | const failEvent = createEventHook()
50 | const successEvent = createEventHook()
51 | uni.request({
52 | url: 'https://www.example.com/request', // 虚拟请求地址
53 | fail(err) {
54 | failEvent.trigger(err) // 失败时触发
55 | },
56 | success(res) {
57 | successEvent.trigger(res) // 成功时触发
58 | },
59 | })
60 |
61 | return {
62 | onFail: failEvent.on, // 失败监听
63 | onSuccess: successEvent.on // 成功监听
64 | }
65 | }
66 |
67 | /**
68 | * 使用时
69 | */
70 | const { onFail, onSuccess } = useUserInfo()
71 |
72 | // 注册失败回调,失败时将被触发
73 | onFail(err => {
74 | console.log(err)
75 | })
76 |
77 | // 注册成功回调,成功时将被触发
78 | onSuccess(res => {
79 | console.log(res)
80 | })
81 | ```
82 |
83 |
84 |
--------------------------------------------------------------------------------
/uni_modules/tob-less/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "tob-less",
3 | "displayName": "tob-less",
4 | "version": "1.0.1",
5 | "description": "主题驱动的uniapp样式库",
6 | "keywords": [
7 | "tob-less",
8 | "theme",
9 | "less",
10 | "css"
11 | ],
12 | "repository": "https://github.com/markthree/tob-less",
13 | "engines": {
14 | "HBuilderX": "^3.1.0"
15 | },
16 | "dcloudext": {
17 | "category": [
18 | "JS SDK",
19 | "通用 SDK"
20 | ],
21 | "sale": {
22 | "regular": {
23 | "price": "0.00"
24 | },
25 | "sourcecode": {
26 | "price": "0.00"
27 | }
28 | },
29 | "contact": {
30 | "qq": ""
31 | },
32 | "declaration": {
33 | "ads": "无",
34 | "data": "无",
35 | "permissions": "无"
36 | },
37 | "npmurl": "https://www.npmjs.com/package/tob-less"
38 | },
39 | "uni_modules": {
40 | "dependencies": [],
41 | "encrypt": [],
42 | "platforms": {
43 | "cloud": {
44 | "tcb": "y",
45 | "aliyun": "y"
46 | },
47 | "client": {
48 | "Vue": {
49 | "vue2": "y",
50 | "vue3": "y"
51 | },
52 | "App": {
53 | "app-vue": "y",
54 | "app-nvue": "n"
55 | },
56 | "H5-mobile": {
57 | "Safari": "u",
58 | "Android Browser": "u",
59 | "微信浏览器(Android)": "y",
60 | "QQ浏览器(Android)": "u"
61 | },
62 | "H5-pc": {
63 | "Chrome": "y",
64 | "IE": "u",
65 | "Edge": "y",
66 | "Firefox": "u",
67 | "Safari": "u"
68 | },
69 | "小程序": {
70 | "微信": "y",
71 | "阿里": "u",
72 | "百度": "u",
73 | "字节跳动": "u",
74 | "QQ": "u"
75 | },
76 | "快应用": {
77 | "华为": "u",
78 | "联盟": "u"
79 | }
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/docs/.vuepress/theme/layouts/404.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
22 |
23 |
404
24 |
The Page
27 |
👉 Go Home
33 |
34 |
35 |

40 |
41 |
42 |
43 |
76 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "tob-use",
3 | "displayName": "tob-use 最高效好用的 composition-api 库",
4 | "version": "1.1.0",
5 | "description": "uniapp 的高效 use 库",
6 | "keywords": [
7 | "use",
8 | "hooks",
9 | "vue3",
10 | "vueuse",
11 | "composition-api"
12 | ],
13 | "repository": "https://github.com/dishait/tob-use",
14 | "engines": {
15 | "HBuilderX": "^3.3.11"
16 | },
17 | "dcloudext": {
18 | "category": [
19 | "JS SDK",
20 | "通用 SDK"
21 | ],
22 | "sale": {
23 | "regular": {
24 | "price": "0.00"
25 | },
26 | "sourcecode": {
27 | "price": "0.00"
28 | }
29 | },
30 | "contact": {
31 | "qq": ""
32 | },
33 | "declaration": {
34 | "ads": "无",
35 | "data": "无",
36 | "permissions": "无"
37 | },
38 | "npmurl": "https://www.npmjs.com/package/tob-use"
39 | },
40 | "uni_modules": {
41 | "dependencies": [],
42 | "encrypt": [],
43 | "platforms": {
44 | "cloud": {
45 | "tcb": "y",
46 | "aliyun": "y"
47 | },
48 | "client": {
49 | "Vue": {
50 | "vue2": "n",
51 | "vue3": "y"
52 | },
53 | "App": {
54 | "app-vue": "y",
55 | "app-nvue": "u"
56 | },
57 | "H5-mobile": {
58 | "Safari": "y",
59 | "Android Browser": "y",
60 | "微信浏览器(Android)": "y",
61 | "QQ浏览器(Android)": "y"
62 | },
63 | "H5-pc": {
64 | "Chrome": "y",
65 | "IE": "n",
66 | "Edge": "y",
67 | "Firefox": "y",
68 | "Safari": "y"
69 | },
70 | "小程序": {
71 | "微信": "y",
72 | "阿里": "y",
73 | "百度": "y",
74 | "字节跳动": "y",
75 | "QQ": "y"
76 | },
77 | "快应用": {
78 | "华为": "y",
79 | "联盟": "y"
80 | }
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/docs/.vuepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 | import { watch } from 'chokidar'
3 | import { remove } from 'fs-extra'
4 | import { ThemeObject } from 'vuepress'
5 | import { touch, useDest } from './shared'
6 | import { _DEV_ } from './shared'
7 |
8 | const theme: ThemeObject = {
9 | name: 'docs',
10 | extends: '@vuepress/theme-default',
11 | layouts: {
12 | '404': resolve(__dirname, './layouts/404.vue')
13 | },
14 | onInitialized(app) {
15 | // 修改 api 文档的侧边栏层级
16 | app.pages.forEach(page => {
17 | if (/^\/api\/.+\.html$/.test(page.pathInferred)) {
18 | page.frontmatter.sidebarDepth = 0
19 | }
20 | })
21 | },
22 | onWatched(app, watchers, restart) {
23 | if (_DEV_) {
24 | // 更新 api 监听器
25 | const flushApiWatcher = watch(
26 | './uni_modules/tob-use/**/*.md',
27 | {
28 | ignoreInitial: true
29 | }
30 | )
31 |
32 | flushApiWatcher.on('change', src => {
33 | const { dest, skip } = useDest(src)
34 | if (skip) {
35 | return
36 | }
37 | touch(dest)
38 | })
39 |
40 | flushApiWatcher.once('add', src => {
41 | const { skip } = useDest(src)
42 | if (skip) {
43 | return
44 | }
45 | restart()
46 | })
47 |
48 | flushApiWatcher.once('unlink', src => {
49 | const { dest, skip } = useDest(src)
50 |
51 | if (skip) {
52 | return
53 | }
54 |
55 | remove(dest)
56 | restart()
57 | })
58 |
59 | // 主题监听器
60 | const themeWatcher = watch(
61 | resolve(__dirname, './index.ts'),
62 | {
63 | ignoreInitial: true
64 | }
65 | )
66 |
67 | // 变更时重启
68 | themeWatcher.on('change', restart)
69 |
70 | watchers.push(themeWatcher, flushApiWatcher)
71 | }
72 | }
73 | }
74 |
75 | export default theme
76 |
--------------------------------------------------------------------------------
/docs/about/index.md:
--------------------------------------------------------------------------------
1 | # 关于
2 |
3 |
4 |
5 | ## 组织 :t-rex:
6 |
7 |
8 | 欢迎关注 [**帝莎编程**](http://dishaxy.dishait.cn/)
9 | - [官网](http://dishaxy.dishait.cn/)
10 | - [Gitee](https://gitee.com/dishait)
11 |
12 | - [Github](https://github.com/dishait)
13 |
14 | - [网易云课堂](https://study.163.com/provider/480000001892585/index.htm?share=2&shareId=480000001892585)
15 |
16 |
17 |
18 |
19 |
20 |
21 | ## 开源 :sauropod:
22 |
23 | ### 模板
24 |
25 | 1. [tov-template](https://github.com/dishait/tov-template)
26 | - `vite + vue3 + ts` 开箱即用现代开发模板
27 |
28 | 2. [vite-plugin-template](https://github.com/dishait/vite-plugin-template)
29 | - 开箱即用的 `vite` 插件模板
30 |
31 |
32 | 3. [vuepress-docs-template](https://github.com/dishait/vuepress-docs-template)
33 | - 基于 `vuepress-next` 的文档模板
34 |
35 |
36 |
37 |
38 |
39 | ### vite
40 |
41 | 1. [vite-auto-import-resolvers](https://github.com/dishait/vite-auto-import-resolvers)
42 | - `unplugin-auto-import` 的 `vite resolver`
43 |
44 | 2. [vite-plugin-watcher](https://github.com/dishait/vite-plugin-watcher)
45 | - `vite` 的文件监听插件
46 |
47 | 3. [vite-plugin-builded-force-exit](https://github.com/dishait/vite-plugin-builded-force-exit)
48 | - `vite` 打包后强制退出的插件
49 |
50 |
51 | 4. [vite-plugin-vue-custom-blocks](https://github.com/dishait/vite-plugin-vue-custom-blocks)
52 | - `vue sfc` 的自定义块 `vite` 插件
53 |
54 |
55 |
56 |
57 | ### uniapp
58 |
59 | 1. [tob-ui](https://github.com/dishait/tob-ui)
60 | - 更现代的 `uniapp ui`
61 |
62 | 2. [tob-less](https://github.com/dishait/tob-less)
63 | - 主题驱动的 `uniapp` 样式库
64 |
65 |
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tob-use",
3 | "version": "1.1.1",
4 | "description": "uniapp 的高效 use 库",
5 | "main": "./dist/index.umd.js",
6 | "module": "./dist/index.es.js",
7 | "exports": {
8 | ".": {
9 | "import": "./dist/index.es.js",
10 | "require": "./dist/index.umd.js"
11 | }
12 | },
13 | "scripts": {
14 | "prepublishOnly": "npm run build",
15 | "auto:create": "node scripts/create.js",
16 | "auto:remove": "node scripts/remove.js",
17 | "docs:dev": "vuepress dev docs",
18 | "docs:build": "vuepress build docs",
19 | "docs:dev:open": "vuepress dev docs --open",
20 | "build": "vite build --config uni_modules/tob-use/vite.config.js",
21 | "release": "bumpp --commit --push --tag && npm publish"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "https://github.com/dishait/tob-use.git"
26 | },
27 | "files": [
28 | "dist"
29 | ],
30 | "keywords": [
31 | "tob",
32 | "use",
33 | "vue3",
34 | "uniapp",
35 | "reactivity",
36 | "composition-api"
37 | ],
38 | "author": {
39 | "name": "markthree",
40 | "email": "1801982702@qq.com",
41 | "url": "https://github.com/markthree"
42 | },
43 | "license": "MIT",
44 | "devDependencies": {
45 | "@markthree/ilazy": "^1.0.2",
46 | "@markthree/node-shared": "^1.3.2",
47 | "@types/node": "^17.0.21",
48 | "@vuepress/plugin-register-components": "^2.0.0-beta.35",
49 | "@vuepress/plugin-search": "^2.0.0-beta.35",
50 | "@vueuse/core": "^7.7.0",
51 | "bumpp": "^7.1.1",
52 | "chokidar": "^3.5.3",
53 | "fast-glob": "^3.2.11",
54 | "fs-extra": "^10.0.1",
55 | "ityped": "^1.0.3",
56 | "unocss": "^0.28.1",
57 | "unplugin-auto-import": "^0.6.1",
58 | "unplugin-vue-components": "^0.17.21",
59 | "vite": "^2.8.5",
60 | "vite-plugin-inspect": "^0.4.3",
61 | "vuepress": "^2.0.0-beta.35"
62 | },
63 | "dependencies": {
64 | "vue": "^3.2.31"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useAsyncQueue/index.js:
--------------------------------------------------------------------------------
1 | import { reactive, ref } from 'vue'
2 | import { noop } from '../../shared/base'
3 |
4 | /**
5 | * 使用异步队列
6 | */
7 | export const useAsyncQueue = (tasks, options = {}) => {
8 | const {
9 | interrupt = true, // 允许失败时打断
10 | onError = noop,
11 | onFinished = noop
12 | } = options
13 |
14 | const promiseState = {
15 | pending: 'pending',
16 | rejected: 'rejected',
17 | fulfilled: 'fulfilled'
18 | }
19 | const initialResult = Array.from(
20 | new Array(tasks.length),
21 | () => ({ state: promiseState.pending, data: null })
22 | )
23 | const result = reactive(initialResult)
24 |
25 | const activeIndex = ref(-1)
26 |
27 | // 无任务时,直接返回
28 | const isEmptyTasks = !tasks || tasks.length === 0
29 | if (isEmptyTasks) {
30 | onFinished()
31 | return {
32 | activeIndex,
33 | result
34 | }
35 | }
36 |
37 | // 更新结果
38 | const updateResult = (state, res) => {
39 | activeIndex.value++
40 | result[activeIndex.value].data = res
41 | result[activeIndex.value].state = state
42 | }
43 |
44 | tasks.reduce((prev, curr) => {
45 | return prev
46 | .then(prevRes => {
47 | // 上一个失败时打断并调用完成回调
48 | const isRejected =
49 | result[activeIndex.value]?.state ===
50 | promiseState.rejected
51 | if (isRejected && interrupt) {
52 | onFinished()
53 | return
54 | }
55 |
56 | return curr(prevRes).then(currentRes => {
57 | updateResult(promiseState.fulfilled, currentRes)
58 | // 结束时调用完成 hook
59 | const isFinished =
60 | activeIndex.value === tasks.length - 1
61 | if (isFinished) {
62 | onFinished()
63 | }
64 |
65 | return currentRes
66 | })
67 | })
68 | .catch(e => {
69 | // 错误处理,调用失败回调
70 | updateResult(promiseState.rejected, e)
71 | onError()
72 | return e
73 | })
74 | }, Promise.resolve())
75 |
76 | return {
77 | activeIndex,
78 | result
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/uni.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里是uni-app内置的常用样式变量
3 | *
4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
6 | *
7 | */
8 |
9 | /**
10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
11 | *
12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
13 | */
14 |
15 | /* 颜色变量 */
16 |
17 | /* 行为相关颜色 */
18 | $uni-color-primary: #007aff;
19 | $uni-color-success: #4cd964;
20 | $uni-color-warning: #f0ad4e;
21 | $uni-color-error: #dd524d;
22 |
23 | /* 文字基本颜色 */
24 | $uni-text-color:#333;//基本色
25 | $uni-text-color-inverse:#fff;//反色
26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
27 | $uni-text-color-placeholder: #808080;
28 | $uni-text-color-disable:#c0c0c0;
29 |
30 | /* 背景颜色 */
31 | $uni-bg-color:#ffffff;
32 | $uni-bg-color-grey:#f8f8f8;
33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色
34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
35 |
36 | /* 边框颜色 */
37 | $uni-border-color:#c8c7cc;
38 |
39 | /* 尺寸变量 */
40 |
41 | /* 文字尺寸 */
42 | $uni-font-size-sm:12px;
43 | $uni-font-size-base:14px;
44 | $uni-font-size-lg:16;
45 |
46 | /* 图片尺寸 */
47 | $uni-img-size-sm:20px;
48 | $uni-img-size-base:26px;
49 | $uni-img-size-lg:40px;
50 |
51 | /* Border Radius */
52 | $uni-border-radius-sm: 2px;
53 | $uni-border-radius-base: 3px;
54 | $uni-border-radius-lg: 6px;
55 | $uni-border-radius-circle: 50%;
56 |
57 | /* 水平间距 */
58 | $uni-spacing-row-sm: 5px;
59 | $uni-spacing-row-base: 10px;
60 | $uni-spacing-row-lg: 15px;
61 |
62 | /* 垂直间距 */
63 | $uni-spacing-col-sm: 4px;
64 | $uni-spacing-col-base: 8px;
65 | $uni-spacing-col-lg: 12px;
66 |
67 | /* 透明度 */
68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
69 |
70 | /* 文章场景相关 */
71 | $uni-color-title: #2C405A; // 文章标题颜色
72 | $uni-font-size-title:20px;
73 | $uni-color-subtitle: #555555; // 二级标题颜色
74 | $uni-font-size-subtitle:26px;
75 | $uni-color-paragraph: #3F536E; // 文章段落颜色
76 | $uni-font-size-paragraph:15px;
77 |
--------------------------------------------------------------------------------
/docs/api/utilities/useConfirmDialog.md:
--------------------------------------------------------------------------------
1 | # useConfirmDialog
2 |
3 | 确认对话框
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```html
10 |
38 |
39 |
40 | 显示 Modal
41 |
42 |
43 |
44 | 确认吗?
45 |
46 |
47 |
48 |
49 |
50 | ```
51 |
52 |
53 |
54 | ### Promise
55 |
56 | ```html
57 |
78 |
79 |
80 | 显示 Modal
81 |
82 |
83 |
84 | 确认吗?
85 |
86 |
87 |
88 |
89 |
90 | ```
91 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useOffsetPagination/index.js:
--------------------------------------------------------------------------------
1 | import { noop } from '../../shared/base'
2 | import { biSyncRef } from '../biSyncRef'
3 | import { useClamp } from '../useClamp'
4 | import {
5 | isRef,
6 | computed,
7 | reactive,
8 | unref,
9 | watch
10 | } from 'vue'
11 |
12 | /**
13 | * 偏移分页
14 | */
15 | export const useOffsetPagination = (options = {}) => {
16 | const {
17 | page = 1,
18 | pageSize = 10,
19 | total = Infinity,
20 | onPageChange = noop,
21 | onPageSizeChange = noop,
22 | onPageCountChange = noop
23 | } = options
24 |
25 | // 当前每页元素数量
26 | const currentPageSize = useClamp(pageSize, 1, Infinity)
27 |
28 | // 总页数
29 | const pageCount = computed(() =>
30 | Math.ceil(unref(total) / unref(currentPageSize))
31 | )
32 |
33 | // 当前第几页
34 | const currentPage = useClamp(page, 1, pageCount)
35 |
36 | // 是否是第一页
37 | const isFirstPage = computed(
38 | () => currentPage.value === 1
39 | )
40 |
41 | // 是否是最后一页
42 | const isLastPage = computed(
43 | () => currentPage.value === pageCount.value
44 | )
45 |
46 | // 同步 第几页
47 | if (isRef(page)) {
48 | biSyncRef(page, currentPage)
49 | }
50 |
51 | // 同步 每页元素数量
52 | if (isRef(pageSize)) {
53 | biSyncRef(pageSize, currentPageSize)
54 | }
55 |
56 | // 上一页
57 | const prev = () => currentPage.value--
58 |
59 | // 下一页
60 | const next = () => currentPage.value++
61 |
62 | const returnValue = {
63 | currentPage,
64 | currentPageSize,
65 | pageCount,
66 | isFirstPage,
67 | isLastPage,
68 | prev,
69 | next
70 | }
71 |
72 | // 当前第几页变化时,触发 onPageChange
73 | watch(currentPage, () => {
74 | onPageChange(reactive(returnValue))
75 | })
76 |
77 | // 当前每页元素数量变化时,触发 onPageSizeChange
78 | watch(currentPageSize, () => {
79 | onPageSizeChange(reactive(returnValue))
80 | })
81 |
82 | // 总页数变化时,触发 onPageCountChange
83 | watch(pageCount, () => {
84 | onPageCountChange(reactive(returnValue))
85 | })
86 |
87 | return returnValue
88 | }
89 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useConfirmDialog/README.md:
--------------------------------------------------------------------------------
1 | # useConfirmDialog
2 |
3 | 确认对话框
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```html
10 |
38 |
39 |
40 | 显示 Modal
41 |
42 |
43 |
44 | 确认吗?
45 |
46 |
47 |
48 |
49 |
50 | ```
51 |
52 |
53 |
54 | ### Promise
55 |
56 | ```html
57 |
78 |
79 |
80 | 显示 Modal
81 |
82 |
83 |
84 | 确认吗?
85 |
86 |
87 |
88 |
89 |
90 | ```
91 |
--------------------------------------------------------------------------------
/docs/api/component/computedInject.md:
--------------------------------------------------------------------------------
1 | # computedInject
2 |
3 | 计算属性型 inject
4 |
5 | ## Usage
6 |
7 | 上层组件提供 `provide`
8 |
9 | ```html
10 |
20 | ```
21 |
22 | 下层组件注入 `injcet`
23 |
24 | ```html
25 |
37 | ```
38 |
39 |
40 |
41 | ### 默认值
42 |
43 | 当不确定上层组件是否提供 `provide` 时,可以设置第三个参数作为默认值
44 |
45 | ```html
46 |
60 | ```
61 |
62 | 工厂函数型默认值
63 |
64 | ```html
65 |
82 | ```
83 |
84 |
85 |
86 | ### setter
87 |
88 | ```html
89 |
103 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/computedInject/README.md:
--------------------------------------------------------------------------------
1 | # computedInject
2 |
3 | 计算属性型 inject
4 |
5 | ## Usage
6 |
7 | 上层组件提供 `provide`
8 |
9 | ```html
10 |
20 | ```
21 |
22 | 下层组件注入 `injcet`
23 |
24 | ```html
25 |
37 | ```
38 |
39 |
40 |
41 | ### 默认值
42 |
43 | 当不确定上层组件是否提供 `provide` 时,可以设置第三个参数作为默认值
44 |
45 | ```html
46 |
60 | ```
61 |
62 | 工厂函数型默认值
63 |
64 | ```html
65 |
82 | ```
83 |
84 |
85 |
86 | ### setter
87 |
88 | ```html
89 |
103 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/useMemoize.md:
--------------------------------------------------------------------------------
1 | # useMemoize
2 |
3 | 使用备份
4 |
5 | 即输入相同参数的情况下,直接走缓存。
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```js
12 | import { useMemoize } from '@/uni_modules/tob-use'
13 |
14 | // 生成数组
15 | const generateArray = length => {
16 | return Array.from({ length }, (_, i) => i)
17 | }
18 |
19 | const useArray = useMemoize(
20 | length => {
21 | return Array.from({ length }, (_, i) => i)
22 | }
23 | )
24 |
25 | const a1 = useArray(1) // 使用长度为 1 的新数组
26 | const a2 = useArray(2) // 使用长度为 2 的新数组
27 |
28 | const a3 = useArray(1) // 从缓存里拿到之前长度为 1 的数组
29 |
30 |
31 | const a4 = useArray.load(1) // 重新生成数组长度为 1 的新数组(即不用缓存里的)
32 |
33 | useArray.cache // 当前缓存,一个 reactive 的 map
34 |
35 | useArray.delete(1) // 将数组长度为 1 的数组从缓存中删除
36 | useArray.clear() // 清除所有缓存
37 | ```
38 |
39 |
40 |
41 | ### 缓存
42 |
43 | 大多数情况你不需要手动生成缓存,`useMemoize` 内部会自动生成 `reactive` 的 `map` 缓存。
44 |
45 | 当然有时候我们希望让两个 `useMemoize` 共用缓存。那么可以这样 👇
46 |
47 | ```ts
48 | import { useMemoize } from '@/uni_modules/tob-use'
49 |
50 | // 被共用的缓存
51 | const cache = new Map()
52 |
53 | const generateArray = length => {
54 | return Array.from({ length }, (_, i) => i)
55 | }
56 |
57 | const useArray1 = useMemoize(generateArray, { cache })
58 | const useArray2 = useMemoize(generateArray, { cache })
59 |
60 | const a1 = useArray1(1) // 使用长度为 1 的新数组
61 |
62 | const a2 = useArray2(1) // 使用缓存里长度为 1 的数组
63 | ```
64 |
65 |
66 |
67 | ### 自定义 Key
68 |
69 | 默认情况下,`useMemoize` 会自动根据函数所有的参数作为缓存的 `key`
70 |
71 | ```ts
72 | import { useMemoize } from '@/uni_modules/tob-use'
73 |
74 | // 生成数组,但可以传入第二个参数递增倍数
75 | const generateArray = (length, multiple = 1) => {
76 | return Array.from({ length }, (_, i) => i * multiple)
77 | }
78 | const useArray = useMemoize(generateArray, {
79 | getKey(length, multiple) {
80 | return length // 默认以所有参数为 key,但这里只让第一个参数为 key
81 | }
82 | })
83 |
84 | const a1 = useArray(10, 2) // 使用长度为 10,2 倍递增的新数组
85 |
86 | // 即使设置了 3 倍递增,但是我们只以第一参数为 key,所以仍然复用缓存
87 | const a2 = useArray(10, 3)
88 | ```
--------------------------------------------------------------------------------
/docs/api/media/createAudio.md:
--------------------------------------------------------------------------------
1 | # createAudio
2 |
3 | :::warning
4 | 暂时不支持小程序端
5 | :::
6 |
7 | 创建音频
8 |
9 | ## Usage
10 |
11 | ### 基础
12 |
13 | ```ts
14 | import { createAudio } from '@/uni_modules/tob-use'
15 |
16 | // createAudio 可接受所有的原生配置,例如 src, autoplay, loop 等
17 | const { toggle } = createAudio({
18 | src: 'your src'
19 | })
20 |
21 | toggle() // 播放,开
22 | toggle() // 暂停,关
23 | toggle() // 播放,开
24 | // ... 不断对当前状态取反
25 |
26 | toggle(false) // 暂停
27 | toggle(true) // 播放
28 |
29 | toggle(true, 'new src') // 播放新的音频
30 | ```
31 |
32 |
33 |
34 | ### 其他
35 |
36 | ```js
37 | import { createAudio } from '@/uni_modules/tob-use'
38 |
39 | const {
40 | play,
41 | stop,
42 | seek,
43 | reset,
44 | audio,
45 | pause,
46 | replay,
47 | destroy,
48 | buffered,
49 | isActive,
50 | duration,
51 | isWaiting,
52 | currentTime,
53 | } = createAudio()
54 |
55 | play('your src') // 播放
56 |
57 | pause() // 暂停
58 |
59 | seek(20) // 跳转到对应位置
60 |
61 | reset() // 重置
62 |
63 | replay() // 重播
64 |
65 | stop() // 停止
66 |
67 | destroy() // 销毁
68 |
69 | isActive.value // 是否播放中
70 |
71 | isWaiting.value // 是否加载数据中
72 |
73 | duration.value // 总时长
74 |
75 | currentTime.value // 当前进度
76 |
77 | buffered.value // 当前缓冲点
78 |
79 | audio // 原生 audio 对象
80 | ```
81 |
82 |
83 |
84 |
85 | ## 注意事项
86 |
87 | ### changing
88 |
89 | 结合原生的 `slider` 组件的 `changing` 时,为了更好的性能,你需要注意 `seek` 的使用
90 |
91 | ```html
92 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/useMemoize/README.md:
--------------------------------------------------------------------------------
1 | # useMemoize
2 |
3 | 使用备份
4 |
5 | 即输入相同参数的情况下,直接走缓存。
6 |
7 | ## Usage
8 |
9 | ### 基础
10 |
11 | ```js
12 | import { useMemoize } from '@/uni_modules/tob-use'
13 |
14 | // 生成数组
15 | const generateArray = length => {
16 | return Array.from({ length }, (_, i) => i)
17 | }
18 |
19 | const useArray = useMemoize(
20 | length => {
21 | return Array.from({ length }, (_, i) => i)
22 | }
23 | )
24 |
25 | const a1 = useArray(1) // 使用长度为 1 的新数组
26 | const a2 = useArray(2) // 使用长度为 2 的新数组
27 |
28 | const a3 = useArray(1) // 从缓存里拿到之前长度为 1 的数组
29 |
30 |
31 | const a4 = useArray.load(1) // 重新生成数组长度为 1 的新数组(即不用缓存里的)
32 |
33 | useArray.cache // 当前缓存,一个 reactive 的 map
34 |
35 | useArray.delete(1) // 将数组长度为 1 的数组从缓存中删除
36 | useArray.clear() // 清除所有缓存
37 | ```
38 |
39 |
40 |
41 | ### 缓存
42 |
43 | 大多数情况你不需要手动生成缓存,`useMemoize` 内部会自动生成 `reactive` 的 `map` 缓存。
44 |
45 | 当然有时候我们希望让两个 `useMemoize` 共用缓存。那么可以这样 👇
46 |
47 | ```ts
48 | import { useMemoize } from '@/uni_modules/tob-use'
49 |
50 | // 被共用的缓存
51 | const cache = new Map()
52 |
53 | const generateArray = length => {
54 | return Array.from({ length }, (_, i) => i)
55 | }
56 |
57 | const useArray1 = useMemoize(generateArray, { cache })
58 | const useArray2 = useMemoize(generateArray, { cache })
59 |
60 | const a1 = useArray1(1) // 使用长度为 1 的新数组
61 |
62 | const a2 = useArray2(1) // 使用缓存里长度为 1 的数组
63 | ```
64 |
65 |
66 |
67 | ### 自定义 Key
68 |
69 | 默认情况下,`useMemoize` 会自动根据函数所有的参数作为缓存的 `key`
70 |
71 | ```ts
72 | import { useMemoize } from '@/uni_modules/tob-use'
73 |
74 | // 生成数组,但可以传入第二个参数递增倍数
75 | const generateArray = (length, multiple = 1) => {
76 | return Array.from({ length }, (_, i) => i * multiple)
77 | }
78 | const useArray = useMemoize(generateArray, {
79 | getKey(length, multiple) {
80 | return length // 默认以所有参数为 key,但这里只让第一个参数为 key
81 | }
82 | })
83 |
84 | const a1 = useArray(10, 2) // 使用长度为 10,2 倍递增的新数组
85 |
86 | // 即使设置了 3 倍递增,但是我们只以第一参数为 key,所以仍然复用缓存
87 | const a2 = useArray(10, 3)
88 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/media/createAudio/README.md:
--------------------------------------------------------------------------------
1 | # createAudio
2 |
3 | :::warning
4 | 暂时不支持小程序端
5 | :::
6 |
7 | 创建音频
8 |
9 | ## Usage
10 |
11 | ### 基础
12 |
13 | ```ts
14 | import { createAudio } from '@/uni_modules/tob-use'
15 |
16 | // createAudio 可接受所有的原生配置,例如 src, autoplay, loop 等
17 | const { toggle } = createAudio({
18 | src: 'your src'
19 | })
20 |
21 | toggle() // 播放,开
22 | toggle() // 暂停,关
23 | toggle() // 播放,开
24 | // ... 不断对当前状态取反
25 |
26 | toggle(false) // 暂停
27 | toggle(true) // 播放
28 |
29 | toggle(true, 'new src') // 播放新的音频
30 | ```
31 |
32 |
33 |
34 | ### 其他
35 |
36 | ```js
37 | import { createAudio } from '@/uni_modules/tob-use'
38 |
39 | const {
40 | play,
41 | stop,
42 | seek,
43 | reset,
44 | audio,
45 | pause,
46 | replay,
47 | destroy,
48 | buffered,
49 | isActive,
50 | duration,
51 | isWaiting,
52 | currentTime,
53 | } = createAudio()
54 |
55 | play('your src') // 播放
56 |
57 | pause() // 暂停
58 |
59 | seek(20) // 跳转到对应位置
60 |
61 | reset() // 重置
62 |
63 | replay() // 重播
64 |
65 | stop() // 停止
66 |
67 | destroy() // 销毁
68 |
69 | isActive.value // 是否播放中
70 |
71 | isWaiting.value // 是否加载数据中
72 |
73 | duration.value // 总时长
74 |
75 | currentTime.value // 当前进度
76 |
77 | buffered.value // 当前缓冲点
78 |
79 | audio // 原生 audio 对象
80 | ```
81 |
82 |
83 |
84 |
85 | ## 注意事项
86 |
87 | ### changing
88 |
89 | 结合原生的 `slider` 组件的 `changing` 时,为了更好的性能,你需要注意 `seek` 的使用
90 |
91 | ```html
92 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | ```
--------------------------------------------------------------------------------
/docs/api/utilities/controlledRef.md:
--------------------------------------------------------------------------------
1 | # controlledRef
2 |
3 | 受控型 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { computed } from 'vue'
11 | import { controlledRef } from '@/uni_modules/tob-use'
12 |
13 | let num = controlledRef(0)
14 | const doubled = computed(() => num.value * 2)
15 |
16 | // 原生行为
17 | num.value = 42
18 | console.log(num.value) // 42
19 | console.log(doubled.value) // 84
20 |
21 | // 设置值,但是不触发更新 (第二参数设置为 false 时)
22 | num.set(30, false)
23 | console.log(num.value) // 30
24 | console.log(doubled.value) // 84 (仍然是 84,不会更新)
25 |
26 | // 偷窥,获取值,但不 track 收集副作用
27 | watchEffect(() => {
28 | console.log(num.peek()) // 30
29 | })
30 |
31 | // 即使更新了依赖
32 | // 也不会 trigger 触发上边的 watchEffect 注册的副作用回调
33 | num.value = 50
34 | console.log(doubled.value) // 100
35 | ```
36 |
37 |
38 |
39 | ### 静默
40 |
41 | 有时候我们不希望 `getter` 访问时 `track` 收集副作用,或 `setter` 设置时 `trigger` 触发副作用。
42 |
43 | ```ts
44 | import { controlledRef } from '@/uni_modules/tob-use'
45 |
46 | const foo = controlledRef('foo')
47 | ```
48 |
49 | ```ts
50 | // 静默访问,以下 api 等效,选择其一即可
51 | foo.get(false)
52 | foo.untrackedGet()
53 | foo.peek()
54 | ```
55 |
56 | ```ts
57 | // 静默设置,以下 api 等效,选择其一即可
58 | foo.set('bar', false)
59 | foo.silentSet('bar')
60 | foo.lay('bar')
61 | ```
62 |
63 |
64 |
65 | ### 配置
66 |
67 | #### onBeforeChange
68 |
69 | 配置 `onBeforeChange` 可以判断是否接受新值
70 |
71 | ```ts
72 | import { controlledRef } from '@/uni_modules/tob-use'
73 |
74 | const num = controlledRef(0, {
75 | onBeforeChange(value, oldValue) {
76 | if (Math.abs(value - oldValue) > 5) {
77 | return false // 返回 false 时,该值被忽略
78 | }
79 | }
80 | })
81 |
82 | num.value = 1
83 | console.log(num.value) // 1
84 |
85 | num.value = 7
86 | console.log(num.value) // 1 (新值被忽略了)
87 | ```
88 |
89 | #### onChanged
90 |
91 | 类似原生的 `watch`,可以监听值的变更。
92 |
93 | ```ts
94 | import { controlledRef } from '@/uni_modules/tob-use'
95 |
96 | const num = controlledRef(0, {
97 | onChanged(value, oldValue) {
98 | console.log(value)
99 | }
100 | })
101 |
102 |
103 | num.value = 1 // 打印 1
104 |
105 | num.value = 2 // 打印 2
106 | ```
107 |
108 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/controlledRef/README.md:
--------------------------------------------------------------------------------
1 | # controlledRef
2 |
3 | 受控型 ref
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | ```js
10 | import { computed } from 'vue'
11 | import { controlledRef } from '@/uni_modules/tob-use'
12 |
13 | let num = controlledRef(0)
14 | const doubled = computed(() => num.value * 2)
15 |
16 | // 原生行为
17 | num.value = 42
18 | console.log(num.value) // 42
19 | console.log(doubled.value) // 84
20 |
21 | // 设置值,但是不触发更新 (第二参数设置为 false 时)
22 | num.set(30, false)
23 | console.log(num.value) // 30
24 | console.log(doubled.value) // 84 (仍然是 84,不会更新)
25 |
26 | // 偷窥,获取值,但不 track 收集副作用
27 | watchEffect(() => {
28 | console.log(num.peek()) // 30
29 | })
30 |
31 | // 即使更新了依赖
32 | // 也不会 trigger 触发上边的 watchEffect 注册的副作用回调
33 | num.value = 50
34 | console.log(doubled.value) // 100
35 | ```
36 |
37 |
38 |
39 | ### 静默
40 |
41 | 有时候我们不希望 `getter` 访问时 `track` 收集副作用,或 `setter` 设置时 `trigger` 触发副作用。
42 |
43 | ```ts
44 | import { controlledRef } from '@/uni_modules/tob-use'
45 |
46 | const foo = controlledRef('foo')
47 | ```
48 |
49 | ```ts
50 | // 静默访问,以下 api 等效,选择其一即可
51 | foo.get(false)
52 | foo.untrackedGet()
53 | foo.peek()
54 | ```
55 |
56 | ```ts
57 | // 静默设置,以下 api 等效,选择其一即可
58 | foo.set('bar', false)
59 | foo.silentSet('bar')
60 | foo.lay('bar')
61 | ```
62 |
63 |
64 |
65 | ### 配置
66 |
67 | #### onBeforeChange
68 |
69 | 配置 `onBeforeChange` 可以判断是否接受新值
70 |
71 | ```ts
72 | import { controlledRef } from '@/uni_modules/tob-use'
73 |
74 | const num = controlledRef(0, {
75 | onBeforeChange(value, oldValue) {
76 | if (Math.abs(value - oldValue) > 5) {
77 | return false // 返回 false 时,该值被忽略
78 | }
79 | }
80 | })
81 |
82 | num.value = 1
83 | console.log(num.value) // 1
84 |
85 | num.value = 7
86 | console.log(num.value) // 1 (新值被忽略了)
87 | ```
88 |
89 | #### onChanged
90 |
91 | 类似原生的 `watch`,可以监听值的变更。
92 |
93 | ```ts
94 | import { controlledRef } from '@/uni_modules/tob-use'
95 |
96 | const num = controlledRef(0, {
97 | onChanged(value, oldValue) {
98 | console.log(value)
99 | }
100 | })
101 |
102 |
103 | num.value = 1 // 打印 1
104 |
105 | num.value = 2 // 打印 2
106 | ```
107 |
108 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/media/useAudio/index.js:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 | import { createAudio } from '../createAudio'
3 | import { useCycleList } from '../../utilities/useCycleList'
4 | import { eagerComputed } from "../../utilities/eagerComputed"
5 |
6 | /**
7 | * 正确化时间
8 | */
9 | const normalizeTime = time => {
10 | if (time === Infinity) return '00:00'
11 |
12 | const division = Math.floor(time / 60)
13 | const remainder = Math.floor(time % 60)
14 | const zero = x => '0'.repeat(2 - String(x).length)
15 | return `${zero(division) + division}:${
16 | zero(remainder) + remainder
17 | }`
18 | }
19 |
20 | /**
21 | * 使用 audio
22 | */
23 | export const useAudio = (list = [], options = {}) => {
24 | const {
25 | play,
26 | stop,
27 | seek,
28 | reset,
29 | audio,
30 | pause,
31 | error,
32 | toggle,
33 | replay,
34 | destroy,
35 | buffered,
36 | duration,
37 | isActive,
38 | isWaiting,
39 | currentTime
40 | } = createAudio({
41 | src: list[0],
42 | ...options
43 | })
44 |
45 | const { state, next, prev, index } = useCycleList(list)
46 |
47 | watch(state, src => play(src))
48 |
49 | // 需要重置
50 | const shouldReset = list.length === 1
51 | // 需要重新播放
52 | const shouldReplay = shouldReset
53 |
54 | audio.onEnded(() => (shouldReset ? reset() : next()))
55 |
56 | // 规范后的总时长
57 | const normalizedDuration = eagerComputed(() => {
58 | return normalizeTime(duration.value)
59 | })
60 |
61 | // 规范化后的进度
62 | const normalizedCurrentTime = eagerComputed(() => {
63 | return normalizeTime(currentTime.value)
64 | })
65 |
66 | return {
67 | play,
68 | stop,
69 | seek,
70 | audio,
71 | error,
72 | pause,
73 | index,
74 | toggle,
75 | replay,
76 | destroy,
77 | buffered,
78 | duration,
79 | isActive,
80 | isWaiting,
81 | currentTime,
82 | normalizedDuration,
83 | normalizedCurrentTime,
84 | src: state,
85 | next: n => {
86 | if (shouldReplay) {
87 | return replay()
88 | } else {
89 | reset()
90 | next(n)
91 | }
92 | },
93 | prev: n => {
94 | if (shouldReplay) {
95 | return replay()
96 | } else {
97 | reset()
98 | prev(n)
99 | }
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/utilities/asyncComputed/index.js:
--------------------------------------------------------------------------------
1 | import { noop } from '../../shared/base'
2 | import { ref, computed, isRef } from 'vue'
3 |
4 | /**
5 | * 异步的计算属性
6 | */
7 | export const asyncComputed = (
8 | evaluationCallback,
9 | initialState,
10 | optionsOrRef
11 | ) => {
12 | const options = formatOptions(optionsOrRef)
13 | const {
14 | lazy = false, // 懒处理
15 | onError = noop, // 错误处理
16 | evaluating = undefined // 异步是否在调用中
17 | } = options
18 |
19 | const started = ref(!lazy)
20 | const current = ref(initialState)
21 | let counter = 0 // 计数器,用来协调异步调用次数
22 |
23 | watchEffect(async onInvalidate => {
24 | if (!started.value) {
25 | return
26 | }
27 |
28 | counter++
29 |
30 | const counterAtBeginning = counter
31 |
32 | let hasFinished = false
33 |
34 | if (evaluating) {
35 | runNextMicroTask(() => {
36 | evaluating.value = true
37 | })
38 | }
39 |
40 | try {
41 | const result = await evaluationCallback(
42 | // 副作用清除函数
43 | cancelCallback => {
44 | onInvalidate(() => {
45 | if (evaluating) {
46 | evaluating.value = false
47 | }
48 | if (!hasFinished) {
49 | cancelCallback()
50 | }
51 | })
52 | }
53 | )
54 |
55 | // 当计算器与当前的调用相同时才允许更新
56 | // 防止多次调用异步触发重复的更新
57 | const shouldUpdate = counterAtBeginning === counter
58 | if (shouldUpdate) {
59 | current.value = result
60 | }
61 | } catch (e) {
62 | // 错误处理,默认为 noop 不处理
63 | onError(e)
64 | } finally {
65 | // 完成后
66 | if (evaluating) {
67 | evaluating.value = false
68 | }
69 | hasFinished = true
70 | }
71 | })
72 |
73 | // lazy 选项开启时,将在第一次 getter 访问时触发
74 | if (lazy) {
75 | return computed(() => {
76 | started.value = true
77 | return current.value
78 | })
79 | }
80 |
81 | return current
82 | }
83 |
84 | /**
85 | * 格式化选项
86 | */
87 | const formatOptions = optionsOrRef => {
88 | let options
89 | if (isRef(optionsOrRef)) {
90 | options = { evaluating: optionsOrRef }
91 | } else {
92 | options = optionsOrRef || {}
93 | }
94 | return options
95 | }
96 |
97 | /**
98 | * 运行在下次微任务
99 | */
100 | const runNextMicroTask = cb => Promise.resolve().then(cb)
101 |
--------------------------------------------------------------------------------
/scripts/remove.js:
--------------------------------------------------------------------------------
1 | const {
2 | noticeFail,
3 | noticeSuccess
4 | } = require('./shared/log')
5 | const { getModulesName } = require('./shared/modules')
6 | const {
7 | useInquirerQuestion,
8 | useInquirerConfirm,
9 | useInquirerList
10 | } = require('@markthree/ilazy')
11 | const {
12 | remove,
13 | writeJson,
14 | createPath,
15 | pathExistsSync
16 | } = require('@markthree/node-shared')
17 | const pagesJson = require('../pages.json')
18 |
19 | const p = createPath(__dirname)
20 |
21 | const autoRemove = async () => {
22 | const type = await useInquirerList(
23 | '请选择需要删除的模块类型',
24 | { choices: ['api', 'page'] }
25 | )
26 |
27 | const n = getModulesName(type)
28 | const sort = await useInquirerList(
29 | `请选择该${n}属于的种类`,
30 | { choices: ['utilities'] }
31 | )
32 |
33 | const name = await useInquirerQuestion(
34 | `请输入该${n}的名字`
35 | )
36 |
37 | const isApi = type === 'api'
38 | if (isApi) {
39 | return await removeApi({ name, type, sort })
40 | }
41 |
42 | const isPage = type === 'page'
43 | if (isPage) {
44 | return await removePage({ name, type, sort })
45 | }
46 | }
47 |
48 | // 删除api
49 | const removeApi = async (options = {}) => {
50 | const { name, sort } = options
51 | const src = p(`../uni_modules/tob-use/${sort}/${name}`)
52 | const shouldRemove = await isWillRemove(src, 'api')
53 | if (shouldRemove) {
54 | await remove(src)
55 | return noticeSuccess('删除')
56 | }
57 | noticeFail('删除')
58 | }
59 |
60 | // 删除页面
61 | const removePage = async (options = {}) => {
62 | const { sort, name } = options
63 | const src = p(`../pages/${sort}/${name}`)
64 | const shouldRemove = await isWillRemove(src, '页面')
65 | if (shouldRemove) {
66 | const path = `pages/${sort}/${name}/${name}`
67 | pagesJson.pages = pagesJson.pages.filter(page => {
68 | return page.path !== path
69 | })
70 | await remove(src)
71 | await writeJson(p('../pages.json'), pagesJson, {
72 | spaces: '\t'
73 | })
74 | return noticeSuccess('删除')
75 | }
76 | noticeFail('删除')
77 | }
78 |
79 | // 判断是否要删除
80 | const isWillRemove = async (src, type = '文件') => {
81 | if (pathExistsSync(src)) {
82 | const isRemove = await useInquirerConfirm(
83 | '再次确认是否删除'
84 | )
85 | return isRemove
86 | }
87 | console.log(`该${type}不存在`)
88 | return false
89 | }
90 |
91 | autoRemove()
92 |
--------------------------------------------------------------------------------
/docs/api/component/useVModel.md:
--------------------------------------------------------------------------------
1 | # useVModel
2 |
3 | 使用 v-model
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | 子组件 👇
10 |
11 | ```html
12 |
13 |
30 | ```
31 |
32 | 父组件 👇
33 |
34 | ```html
35 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | ```
47 |
48 |
49 |
50 | ### key
51 |
52 | 我们可以通过第二个参数设置 `key` 👇
53 |
54 | ```html
55 |
56 |
74 | ```
75 |
76 | 父组件 👇
77 |
78 | ```html
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | ```
87 |
88 |
89 |
90 |
91 | ### 选项
92 |
93 | 第四个参数可以设置一些选项,不过大多数情况下,你并不需要关注
94 |
95 | ```html
96 |
112 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/component/useVModel/README.md:
--------------------------------------------------------------------------------
1 | # useVModel
2 |
3 | 使用 v-model
4 |
5 | ## Usage
6 |
7 | ### 基础
8 |
9 | 子组件 👇
10 |
11 | ```html
12 |
13 |
30 | ```
31 |
32 | 父组件 👇
33 |
34 | ```html
35 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | ```
47 |
48 |
49 |
50 | ### key
51 |
52 | 我们可以通过第二个参数设置 `key` 👇
53 |
54 | ```html
55 |
56 |
74 | ```
75 |
76 | 父组件 👇
77 |
78 | ```html
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | ```
87 |
88 |
89 |
90 |
91 | ### 选项
92 |
93 | 第四个参数可以设置一些选项,不过大多数情况下,你并不需要关注
94 |
95 | ```html
96 |
112 | ```
--------------------------------------------------------------------------------
/docs/api/media/useAudio.md:
--------------------------------------------------------------------------------
1 | # useAudio
2 |
3 | :::warning
4 | 暂时不支持小程序端
5 | :::
6 |
7 | 使用音频
8 |
9 | ## Usage
10 |
11 | ### 基础
12 |
13 | ```ts
14 | import { useAudio } from '@/uni_modules/tob-use'
15 |
16 | // 播放列表
17 | const playlist = ['src1', 'src2', '...']
18 |
19 | const {
20 | prev,
21 | next,
22 | toggle,
23 | } = useAudio(playlist)
24 |
25 | toggle() // 播放,开
26 | toggle() // 暂停,关
27 | toggle() // 播放,开
28 | // ... 不断对当前状态取反
29 |
30 | toggle(false) // 暂停
31 | toggle(true) // 播放
32 |
33 | toggle(true, 'new src') // 播放新的音频
34 |
35 | prev() // 上一首
36 | next() // 下一首
37 |
38 | prev(2) // 上上首
39 | next(2) // 下下首
40 | ```
41 |
42 |
43 |
44 | ### 其他
45 |
46 | ```js
47 | import { useAudio } from '@/uni_modules/tob-use'
48 |
49 | // 播放列表
50 | const playlist = ['src1', 'src2', '...']
51 |
52 | // useAudio 的第二参数可接受所有的原生配置,例如 src, autoplay, loop 等
53 | const {
54 | src,
55 | play,
56 | stop,
57 | seek,
58 | reset,
59 | index,
60 | audio,
61 | pause,
62 | replay,
63 | destroy,
64 | buffered,
65 | isActive,
66 | duration,
67 | isWaiting,
68 | currentTime,
69 | normalizedDuration,
70 | normalizedCurrentTime
71 | } = useAudio(playlist, {
72 | autoplay: true // 设置自动播放
73 | })
74 |
75 | play('your src') // 播放
76 |
77 | pause() // 暂停
78 |
79 | seek(20) // 跳转到对应位置
80 |
81 | reset() // 重置
82 |
83 | replay() // 重播
84 |
85 | stop() // 停止
86 |
87 | destroy() // 销毁
88 |
89 | isActive.value // 是否播放中
90 |
91 | isWaiting.value // 是否加载数据中
92 |
93 | duration.value // 总时长
94 |
95 | currentTime.value // 当前进度
96 |
97 | buffered.value // 当前缓冲点
98 |
99 | src.value // 当前播放的音频地址
100 |
101 | index.value // 当前播放的 index
102 |
103 | audio // 原生 audio 对象
104 |
105 | normalizedDuration.value // 规范化后的时长,即 00:00 格式
106 | normalizedCurrentTime.value // 规范化后的当前进度,即 00:00 格式
107 | ```
108 |
109 |
110 |
111 |
112 | ## 注意事项
113 |
114 | ### changing
115 |
116 | 结合原生的 `slider` 组件的 `changing` 时,为了更好的性能,你需要注意 `seek` 的使用
117 |
118 | ```html
119 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/ignorableWatch/index.js:
--------------------------------------------------------------------------------
1 | import { ref, watch } from 'vue'
2 | import {
3 | bypassFilter,
4 | createFilterWrapper
5 | } from '../../shared/filters'
6 | import { noop } from '../../shared/base'
7 |
8 | /**
9 | * 可忽略的监听
10 | */
11 | export const ignorableWatch = (
12 | source,
13 | cb,
14 | options = {}
15 | ) => {
16 | const { eventFilter = bypassFilter, ...watchOptions } =
17 | options
18 |
19 | const filteredCb = createFilterWrapper(eventFilter, cb)
20 |
21 | let stop
22 | let ignoreUpdates
23 | let ignorePrevAsyncUpdates
24 |
25 | const syncFlush = watchOptions.flush === 'sync'
26 | if (syncFlush) {
27 | const ignore = ref(false)
28 |
29 | ignorePrevAsyncUpdates = noop
30 |
31 | // syncFlush 同步更新时,直接加锁进行更新
32 | ignoreUpdates = updater => {
33 | ignore.value = true
34 | updater()
35 | ignore.value = false
36 | }
37 |
38 | stop = watch(
39 | source,
40 | (...args) => {
41 | if (!ignore.value) filteredCb(...args)
42 | },
43 | watchOptions
44 | )
45 | } else {
46 | // 临时数组,用来存储 watch 之后的 stop
47 | const disposables = []
48 |
49 | const syncCounter = ref(0) // 同步计数器
50 | const ignoreCounter = ref(0) // 忽略计数器
51 |
52 | // 忽略上一次同步更新(使得忽略计数器与同步计数器相同)
53 | ignorePrevAsyncUpdates = () => {
54 | ignoreCounter.value = syncCounter.value
55 | }
56 |
57 | // 监听源更新,递增同步计数器,并收集其 stop
58 | disposables.push(
59 | watch(
60 | source,
61 | () => {
62 | syncCounter.value++
63 | },
64 | { ...watchOptions, flush: 'sync' }
65 | )
66 | )
67 |
68 | // 忽略更新 (调用回调的同时更新忽略计数器)
69 | ignoreUpdates = updater => {
70 | const syncCounterPrev = syncCounter.value
71 | updater()
72 | ignoreCounter.value +=
73 | syncCounter.value - syncCounterPrev
74 | }
75 |
76 | // 重置所有计数器
77 | const resetAllCounter = () => {
78 | syncCounter.value = 0
79 | ignoreCounter.value = 0
80 | }
81 |
82 | // 监听监听源更新,判断是否忽略副作用,并收集其 stop
83 | disposables.push(
84 | watch(
85 | source,
86 | (...args) => {
87 | // 忽略计数器存在并与同步计数器相同时,需要忽略此次更新
88 | const ignore =
89 | ignoreCounter.value > 0 &&
90 | ignoreCounter.value === syncCounter.value
91 | // 重置所有计数器
92 | resetAllCounter()
93 | if (ignore) return
94 |
95 | filteredCb(...args)
96 | },
97 | watchOptions
98 | )
99 | )
100 |
101 | stop = () => {
102 | // stop 掉所有的副作用
103 | disposables.forEach(fn => fn())
104 | }
105 | }
106 |
107 | return { stop, ignoreUpdates, ignorePrevAsyncUpdates }
108 | }
109 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/media/useAudio/README.md:
--------------------------------------------------------------------------------
1 | # useAudio
2 |
3 | :::warning
4 | 暂时不支持小程序端
5 | :::
6 |
7 | 使用音频
8 |
9 | ## Usage
10 |
11 | ### 基础
12 |
13 | ```ts
14 | import { useAudio } from '@/uni_modules/tob-use'
15 |
16 | // 播放列表
17 | const playlist = ['src1', 'src2', '...']
18 |
19 | const {
20 | prev,
21 | next,
22 | toggle,
23 | } = useAudio(playlist)
24 |
25 | toggle() // 播放,开
26 | toggle() // 暂停,关
27 | toggle() // 播放,开
28 | // ... 不断对当前状态取反
29 |
30 | toggle(false) // 暂停
31 | toggle(true) // 播放
32 |
33 | toggle(true, 'new src') // 播放新的音频
34 |
35 | prev() // 上一首
36 | next() // 下一首
37 |
38 | prev(2) // 上上首
39 | next(2) // 下下首
40 | ```
41 |
42 |
43 |
44 | ### 其他
45 |
46 | ```js
47 | import { useAudio } from '@/uni_modules/tob-use'
48 |
49 | // 播放列表
50 | const playlist = ['src1', 'src2', '...']
51 |
52 | // useAudio 的第二参数可接受所有的原生配置,例如 src, autoplay, loop 等
53 | const {
54 | src,
55 | play,
56 | stop,
57 | seek,
58 | reset,
59 | index,
60 | audio,
61 | pause,
62 | replay,
63 | destroy,
64 | buffered,
65 | isActive,
66 | duration,
67 | isWaiting,
68 | currentTime,
69 | normalizedDuration,
70 | normalizedCurrentTime
71 | } = useAudio(playlist, {
72 | autoplay: true // 设置自动播放
73 | })
74 |
75 | play('your src') // 播放
76 |
77 | pause() // 暂停
78 |
79 | seek(20) // 跳转到对应位置
80 |
81 | reset() // 重置
82 |
83 | replay() // 重播
84 |
85 | stop() // 停止
86 |
87 | destroy() // 销毁
88 |
89 | isActive.value // 是否播放中
90 |
91 | isWaiting.value // 是否加载数据中
92 |
93 | duration.value // 总时长
94 |
95 | currentTime.value // 当前进度
96 |
97 | buffered.value // 当前缓冲点
98 |
99 | src.value // 当前播放的音频地址
100 |
101 | index.value // 当前播放的 index
102 |
103 | audio // 原生 audio 对象
104 |
105 | normalizedDuration.value // 规范化后的时长,即 00:00 格式
106 | normalizedCurrentTime.value // 规范化后的当前进度,即 00:00 格式
107 | ```
108 |
109 |
110 |
111 |
112 | ## 注意事项
113 |
114 | ### changing
115 |
116 | 结合原生的 `slider` 组件的 `changing` 时,为了更好的性能,你需要注意 `seek` 的使用
117 |
118 | ```html
119 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | ```
--------------------------------------------------------------------------------
/uni_modules/tob-use/watch/until/index.js:
--------------------------------------------------------------------------------
1 | import { unref, watch } from 'vue'
2 | import { promiseTimeout } from '../../shared/base'
3 |
4 | /**
5 | * 直到
6 | */
7 | export const until = r => {
8 | let isNot = false
9 |
10 | // 匹配,接收回调 condition,返回 false 即不匹配
11 | const toMatch = (condition, options = {}) => {
12 | let {
13 | timeout,
14 | deep = false,
15 | flush = 'sync',
16 | throwOnTimeout
17 | } = options
18 | let stop = null
19 | const watcher = new Promise(resolve => {
20 | stop = watch(
21 | r,
22 | v => {
23 | if (condition(v) === !isNot) {
24 | stop?.()
25 | resolve()
26 | }
27 | },
28 | {
29 | flush,
30 | deep,
31 | immediate: true
32 | }
33 | )
34 | })
35 |
36 | const promises = [watcher]
37 | if (timeout) {
38 | promises.push(
39 | promiseTimeout(timeout, throwOnTimeout).finally(
40 | () => stop?.()
41 | )
42 | )
43 | }
44 |
45 | return Promise.race(promises)
46 | }
47 |
48 | // 是否为 第一参数 value
49 | const toBe = (value, options) =>
50 | toMatch(v => v === unref(value), options)
51 |
52 | // 是否为 truthy
53 | const toBeTruthy = options =>
54 | toMatch(v => Boolean(v), options)
55 |
56 | // 是否为 null
57 | const toBeNull = options => toBe(null, options)
58 |
59 | // 是否未定义
60 | const toBeUndefined = options => toBe(undefined, options)
61 |
62 | // 是否为 NaN
63 | const toBeNaN = options => toMatch(Number.isNaN, options)
64 |
65 | // 是否为指定类数组内的值
66 | const toContains = (value, options) => {
67 | return toMatch(v => {
68 | const array = Array.from(v)
69 | return (
70 | array.includes(value) ||
71 | array.includes(unref(value))
72 | )
73 | }, options)
74 | }
75 |
76 | // 是否变更了
77 | const changed = options => changedTimes(1, options)
78 |
79 | // 是否变更了 n 次
80 | const changedTimes = (n = 1, options) => {
81 | let count = -1
82 | return toMatch(() => {
83 | count += 1
84 | return count >= n
85 | }, options)
86 | }
87 |
88 | if (Array.isArray(unref(r))) {
89 | const instance = {
90 | toMatch,
91 | toContains,
92 | changed,
93 | changedTimes,
94 | get not() {
95 | isNot = !isNot
96 | return this
97 | }
98 | }
99 | return instance
100 | } else {
101 | const instance = {
102 | toMatch,
103 | toBe,
104 | toBeTruthy,
105 | toBeNull,
106 | toBeNaN,
107 | toBeUndefined,
108 | changed,
109 | changedTimes,
110 | get not() {
111 | isNot = !isNot
112 | return this
113 | }
114 | }
115 |
116 | return instance
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/uni_modules/tob-use/state/useStorage/index.js:
--------------------------------------------------------------------------------
1 | import { ref, shallowRef, unref } from 'vue'
2 | import { pausableWatch } from '../../watch/pausableWatch'
3 | import { guessSerializerType } from './guess'
4 |
5 | export const StorageSerializers = {
6 | boolean: {
7 | read: (v) => v === 'true',
8 | write: (v) => String(v)
9 | },
10 | object: {
11 | read: (v) => JSON.parse(v),
12 | write: (v) => JSON.stringify(v)
13 | },
14 | number: {
15 | read: (v) => Number.parseFloat(v),
16 | write: (v) => String(v)
17 | },
18 | any: {
19 | read: (v) => v,
20 | write: (v) => String(v)
21 | },
22 | string: {
23 | read: (v) => v,
24 | write: (v) => String(v)
25 | },
26 | map: {
27 | read: (v) => new Map(JSON.parse(v)),
28 | write: (v) => JSON.stringify(Array.from(v.entries()))
29 | },
30 | set: {
31 | read: (v) => new Set(JSON.parse(v)),
32 | write: (v) => JSON.stringify(Array.from(v))
33 | },
34 | date: {
35 | read: (v) => new Date(v),
36 | write: (v) => v.toISOString()
37 | }
38 | }
39 |
40 | export function useStorage(key, initialValue, options = {}) {
41 | const {
42 | flush = 'pre',
43 | deep = true,
44 | writeDefaults = true,
45 | shallow,
46 | eventFilter,
47 | onError = (e) => {
48 | console.error(e)
49 | }
50 | } = options
51 | const data = (shallow ? shallowRef : ref)(initialValue)
52 | const rawInit = unref(initialValue)
53 | const type = guessSerializerType(rawInit)
54 | const serializer = StorageSerializers[type]
55 |
56 | const { pause, resume } = pausableWatch(data, () => write(data.value), {
57 | flush,
58 | deep,
59 | eventFilter
60 | })
61 |
62 | update()
63 |
64 | return data
65 |
66 | function write(v) {
67 | try {
68 | if (v == null) {
69 | uni.removeStorageSync(key)
70 | } else {
71 | uni.setStorageSync(key, serializer.write(v))
72 | }
73 | } catch (e) {
74 | onError(e)
75 | }
76 | }
77 |
78 | function read(event) {
79 | if (event && event.key !== key) {
80 | return
81 | }
82 |
83 | pause()
84 |
85 | try {
86 | const rawValue = event ? event.newValue : uni.getStorageSync(key)
87 | if (rawValue == null || rawValue == '') {
88 | if (writeDefaults && rawInit !== null) {
89 | uni.setStorageSync(key, serializer.write(rawInit))
90 | }
91 | return rawInit
92 | } else if (typeof rawValue !== 'string') {
93 | return rawValue
94 | } else {
95 | return serializer.read(rawValue)
96 | }
97 | } catch (e) {
98 | onError(e)
99 | } finally {
100 | resume()
101 | }
102 | }
103 |
104 | function update(event) {
105 | if (event && event.key !== key) {
106 | return
107 | }
108 | data.value = read(event)
109 | }
110 | }
111 |
--------------------------------------------------------------------------------