Exciting news!Announcing our $4.6M Series Seed. Learn more
Socket
LoveBlogFAQ
Install
Log in

kayran

Package Overview
Dependencies
2
Maintainers
1
Versions
21
Issues
File Explorer

Advanced tools

kayran

A scattered collection of utilities

    0.4.9latest

Version published
Maintainers
1
Yearly downloads
6,632
increased by779.58%

Weekly downloads

Readme

Source

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


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>

FAQs

What is kayran?

A scattered collection of utilities

Is kayran popular?

The npm package kayran receives a total of 137 weekly downloads. As such, kayran popularity was classified as not popular.

Is kayran well maintained?

We found that kayran demonstrated a healthy version release cadence and project activity. It has 1 open source maintainer collaborating on the project.

Last updated on 28 Mar 2022
Socket

Product

Subscribe to our newsletter

Get open source security insights delivered straight into your inbox. Be the first to learn about new features and product updates.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc