This package has been deprecated

Author message:

Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

kayran

0.4.9 • Public • Published

kayran / 七零八碎工具函数合集

Installation

NPM

pnpm add kayran lodash-es

waitFor / 以优雅方式书写 await

Param

/**
 * @param {Promise} 需要包装的Promise
 * @returns {any[]} [0]为Promise.prototype.then返回的结果,[1]为Promise.prototype.catch返回的结果
 */
// 示例

import { waitFor } from 'kayran'

const [res] = await waitFor(new Promise((resolve, reject) => {
  resolve('res')
}))
console.log(res) // 'res'

const [, err] = await waitFor(new Promise((resolve, reject) => {
  reject('err')
}))
console.log(err) // 'err'

getMediaDuration / 获取音视频文件的时长

Param

/**
 * @param {File|string} 音视频url或二进制文件
 * @returns {Promise<number>} 时长 单位秒 四舍五入
 */
// 示例

import { getMediaDuration } from 'kayran'

getMediaDuration('https://xxx.mp4')

typeOf / 获取变量的精确类型

动机:原生js的typeof等类型检测手段都存在各种缺陷

Param

/**
 * @param {any} 需要判断的变量
 * @returns {string} 变量类型(全小写) 如string null undefined file...
 */
// 示例

import { typeOf } from 'kayran'

typeOf(1) // 'number'

isEllipsis / 判断dom是否触发溢出省略(text-overflow: ellipsis)

Param

/**
 * @param {Element} 需要判断的元素
 * @returns {boolean} 是否触发溢出省略
 */
// 示例

import { isEllipsis } from 'kayran'

isEllipsis(document.querySelector('.text'))

isEmpty & notEmpty / 判空 & 判非空

notEmpty() 等同于 !isEmpty()

Param

/**
 * @param {any} 需要判断的变量
 * @returns {boolean} 结果
 */
// 示例

import { isEmpty, notEmpty } from 'kayran'

isEmpty(0)  // false
isEmpty({}) // true
isEmpty([]) // true

jsonToFormData / json转FormData

Param

/**
 * @param {object} 需要转换的对象
 * @param {(value?: any, key?: any) => any} mapFn 每个属性会执行该回调函数,返回值为新的属性值
 * @returns {FormData} 转换后的FormData实例
 */
// 示例

import { jsonToFormData } from 'kayran'

const formData = jsonToFormData({
  a: 1
})

formData.get('a') // '1'
// 绑定到FormData上,像Array.from一样使用

import { jsonToFormData } from 'kayran'

if (FormData.from === undefined) {
  FormData.from = jsonToFormData
}

const formData = FormData.from({
  a: '1',
  b: '2'
})
// mapFn示例

import { jsonToFormData } from 'kayran'

const formData = jsonToFormData({
  a: 1
}, v => v + 1)

formData.get('a') // '2'

::: tip
回调函数的返回值为undefined时,该元素不会被添加到FormData实例中(类似filter效果)。 :::


pickDeepBy / lodash-pickBy的递归版本

Param

/**
 * @param {object} obj 原始对象
 * @param {(value?: any, key?: any) => boolean} predicate 每个属性都会调用的方法
 * @returns {object} 新的对象
 */
// 示例

import { pickDeepBy } from 'kayran'

pickDeepBy({
  a: 1,
  b: NaN
}, (v, k) => ![NaN, null, undefined].includes(v))

// { a: 1 }

pickDeepBy不会改变原始对象。


isSameOrigin / 判断是否同源

Param

/**
 * @param {string} url 需要判断的url
 * @returns {boolean}
 */
// 示例

import { isSameOrigin } from 'kayran'

isSameOrigin('www.google.com')

parseQueryString / 获取 url 中某个查询参数的值

Param

/**
 * 获取当前url某个查询参数的值
 * 支持微信公众号授权特例:授权后会重定向回来并在链接中加入一个code参数 但微信没有考虑hash路由的情况 所以获取这个code需要特殊处理
 * @param {object}
 *        {string} key 查询参数的key 如果为空 则返回查询参数映射的对象 可以解构使用
 *        {string} [mode='hash'] router模式 可选值'history'/'hash'
 *        {boolean} del 是否在url中删除该值(删除会引发页面刷新)
 * @returns {string|object} 查询参数中key对应的value / 如果key为空 则返回查询参数整个对象
 */
// 示例

import { parseQueryString } from 'kayran'

const code = parseQueryString('code')

//or

const { code } = parseQueryString()

注意:如果search和hash中同时包含code 如http://localhost:8080/?code=1#/?code=2 取的是search中的code 即返回1


loadLink / 动态加载link

Param

/**
 * @param {string|object} src link url
 * @returns {Promise}
 */
// 示例

import { loadLink } from 'kayran'

await loadLink('https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css')

loadScript / 动态加载js

Param

/**
 * @param {string|object} src 脚本url
 * @returns {Promise}
 */
// 示例

import { loadScript } from 'kayran'

loadScript('https://cdn.jsdelivr.net/npm/vue/dist/vue.js').then(e => {
  console.log(Vue)
})

loadStyle / 动态加载style

Param

/**
 * @param {string|object|HTMLElement} arg style元素的innerText 或传对象指定style的各项属性 或style元素本身
 * @returns {Promise<HTMLElement>}
 */
// 示例

import { loadStyle } from 'kayran'

await loadStyle(`
ul {
  list-style: none;
}
`)

getFinalProp / 获取最终prop(适用于组件开发者)

Vue提供了prop的局部配置和默认值配置,但在封装组件时,还会非常需要一个“全局配置”,否则可能导致每个组件实例进行重复的配置。

举个例子,Element 的size与zIndex就是支持全局配置的。

当配置多了以后,由于存在不同的优先级,最终组件采用的是哪一项配置,需要进行一定的判断,

在涉及到对象和函数时,判断可能会变得相当复杂。

getFinalProp的作用就是帮助你计算出最终的配置。

Features

  • 和Vue的props一样,提供是否必传、数据类型和自定义的校验
  • 对于plain object类型的prop,支持深合并、浅合并和直接覆盖
  • 对于function类型的prop,支持融合、直接覆盖
  • 支持将对象的键统一为驼峰命名
  • 支持动态生成默认值

Param

/**
 * @param {any[]} propSequence - prop序列(优先级从高到低,最后是默认值)
 * @param {object} [config] - 配置
 * @param {string} [config.name] - prop名称,用于报错提示
 * @param {string|string[]} [config.type] - 数据类型校验
 * @param {any} [config.default] - 默认值(显式)
 * @param {boolean} [config.defaultIsDynamic = false] - 动态生成默认值
 * @param {boolean} [config.required = false] - 是否必传校验
 * @param {function} [config.validator] - 自定义校验
 * @param {string} [config.camelCase = true] - 是否将对象的键统一为驼峰命名
 * @param {false|string} [config.mergeObject = 'deep'] - 合并对象的方式
 * @param {boolean} [config.mergeObjectApplyOnlyToDefault = false] - mergeObject仅作用于default
 * @param {false|((accumulator, currentValue, index?, array?) => Function)} [config.mergeFunction = false] - 融合函数的方式
 * @param {boolean} [config.mergeFunctionApplyOnlyToDefault = true] - mergeFunction仅作用于default
 * @returns {any} 最终的prop
 */
// 示例

import { getFinalProp } from 'kayran'

getFinalProp([1, 2, undefined]) // 1

怎么判断某个prop有没有传?

以该prop是否全等于undefined作为标识

config.mergeObject

  • 'deep': 深合并,高权重prop的对象键会覆盖低权重prop的同名键,包含嵌套的对象(默认值)
  • 'shallow': 浅合并,高权重prop的对象键会覆盖低权重prop的同名键,不含嵌套的对象
  • false: 不合并,直接覆盖,高权重prop的对象会直接覆盖低权重prop的对象,与值类型的表现一致

config.mergeObjectApplyOnlyToDefault

默认关闭,仅在mergeObject开启时有效。

开启时,mergeObject的规则仅会应用于最后与default进行比对的环节中,之前的对象依然会直接覆盖。

关闭时,mergeObject的规则会应用至所有对象类型prop的权重比对中。

使用场景:组件作者想要将组件内部的配置与组件使用者的配置进行合并,但组件使用者自身的各级配置依然保持直接覆盖的规则。

config.mergeFunction

使用场景:在封装组件时,你可能需要通过配置选项的方式监听底层依赖的某些事件,

在将该依赖的配置选项暴露出去时,组件使用者的配置就会与你的配置发生冲突。

mergeFunction提供定制化的方式来融合函数类型的prop。

举个例子,知名的富文本库tinymce的配置选项中有一个叫 init_instance_callback 的回调,

在封装这个库时,可以藉此来做一些初始化的工作,为了不破坏组件的灵活性,也会将tinymce的配置选项暴露出去,

问题来了,组件使用者一旦配置了这个回调,就会与你的配置发生冲突。

与其他数据类型的配置不同的是,函数类型的prop,往往不期望被用户的配置直接覆盖掉,会有需要进行“融合”的需求。

融合:既执行组件使用者配置的函数,也执行组件内部配置的函数。

函数类型的prop包括两种情况:

  • prop本身是函数
  • prop是含有函数属性的对象

getFinalProp内部使用 Array.prototype.reduce 来执行函数融合,mergeFunction将被用作参数1。

getFinalProp([
  () => {
    console.log('我是参数1')
  },
  () => {
    console.log('我是参数2')
  }
], {
  default: () => {
    console.log('我是显式默认值')
  },
  mergeFunction: (accumulator, item) => (...args) => {
    accumulator(...args)
    item?.(...args)
  },
  mergeFunctionApplyOnlyToDefault: false,
})()

// 结果会打印 '我是显式默认值' '我是参数2' '我是参数1' 

config.mergeFunctionApplyOnlyToDefault

默认开启,仅在mergeFunction开启时有效。

函数融合毕竟是一个特殊行为,往往只有组件作者会用到这个功能,

对于组件使用者来说,函数类型的配置可能更希望的是和其他原始类型一样,直接覆盖掉就好了。

开启时,mergeFunction的规则仅会应用于最后与default进行比对的环节中,之前的函数依然会直接覆盖。

关闭时,mergeFunction的规则会应用至所有函数类型prop的权重比对中。

config.default

显式指定默认值,如果没有开启 mergeObjectApplyOnlyToDefaultmergeFunctionApplyOnlyToDefault 的话,则没有必要使用该参数,将默认值放在 propSequence 的末尾即可。

config.camelCase

Vue的prop同时支持驼峰和短横线格式,如果组件使用者同时传了同一个prop的两种格式,值还是不相同的,问题来了,此时应该取哪一个值?

在多个配置进行合并时,结果会更加难以预测,所以getFinalProp在合并对象后默认将对象的键统一为驼峰命名。

::: tip 为什么不默认使用短横线命名?
参见Vue官方风格指南 :::

动态生成默认值

使用场景:需要根据组件使用者传的参数来决定默认值

// 示例

getFinalProp([{
  a: {
    a: 1
  }
}, {
  a: {
    a: 2,
    b: 1
  }
}], {
  // userProp是参数1的计算结果
  default: userProp => ({
    a: {
      c: userProp.a.a === 1 ? 1 : null
    }
  }),
  defaultIsDynamic: true,
})

/**
 * 将得到:
 * {
 *   a: {
 *     a: 1,
 *     b: 1,
 *     c: 1
 *   }
 * }
 */

getGlobalAttrs / 获取全局attrs(适用于组件开发者)

在Vue组件中,声明过的prop可以通过 this.$props 获取,没有声明的可以通过 this.$attrs 获取,

但是全局配置就无法区分哪部分是props哪部分是attrs了。

getGlobalAttrs就是帮助你获取全局配置中的attrs的。

使用场景:二次封装组件时,往往需要使用 v-bind="$attrs" 来实现不破坏底层组件的原生能力,

getGlobalAttrs就是在此基础上提供全局配置的能力。

Param

/**
 * @param {object} globalConfig - 组件使用者的全局配置
 * @param {object} props - 组件内部的props对象
 * @returns {object} globalAttrs - 全局配置中的attrs部分
 */

用于Vue3(script setup)

<!-- 示例 -->

<template>
  <某底层组件 v-bind="Attrs"/>
</template>

<script setup>
import { computed, useAttrs, toRaw } from 'vue'
import { getFinalProp, getGlobalAttrs } from 'kayran'
import globalConfig from './config'

const props = defineProps(['modelValue'])

// Attrs即为局部与全局attrs经过权重计算得到的结果
const Attrs = computed(() => getFinalProp([
  { ...useAttrs() },
  getGlobalAttrs(globalConfig, toRaw(props)),
]))
</script>

用于Vue3

<!-- 示例 -->

<template>
  <某底层组件 v-bind="Attrs"/>
</template>

<script>
import { defineComponent, computed, toRaw } from 'vue'
import { getFinalProp, getGlobalAttrs } from 'kayran'
import globalConfig from './config'

export default defineComponent({
  setup (props, { attrs }) {
    // Attrs即为局部与全局attrs经过权重计算得到的结果
    const Attrs = computed(() => getFinalProp([
      { ...attrs },
      getGlobalAttrs(globalConfig, toRaw(props)),
    ]))
    
    return {
      Attrs,
    }
  }
})
</script>

用于Vue2

<!-- 示例 -->

<template>
  <某底层组件 v-bind="Attrs"/>
</template>

<script>
import { getFinalProp, getGlobalAttrs } from 'kayran'
import globalConfig from './config'

export default {
  computed: {
    // Attrs即为局部与全局attrs经过权重计算得到的结果
    Attrs () {
      return getFinalProp([
        this.$attrs,
        getGlobalAttrs(globalConfig, this.$props)
      ])
    }
  }
}
</script>

Readme

Keywords

none

Package Sidebar

Install

npm i kayran

Weekly Downloads

59

Version

0.4.9

License

MIT

Unpacked Size

93.6 kB

Total Files

5

Last publish

Collaborators

  • cloydlau