README
plain-kit / 朴素工具包
Features
- 管理后台生态圈
- 推荐直接使用管理后台脚手架搭配代码生成器 可以做到开箱即用
- 文档略长 是考虑到了开发中个性化的方方面面 尽可能实现动态可配 照顾到各种特殊情况
- 趁手小型组件
- 常用工具函数
Installation
$ yarn add plain-kit
依赖项:vue element-ui
如果你仅使用少量组件或函数 建议按需引入
babel7以上按需引入步骤:
$ yarn add babel-plugin-import --dev
- 在
babel.config.js
中增加如下配置:
module.exports = {
plugins: [
['import', {
libraryName: 'plain-kit',
libraryDirectory: 'lib',
style: false,
camel2DashComponentName: false
}, 'plain-kit']
]
}
管理后台生态圈
main.js
import request from '@/utils/request' // 你的axios封装
import { AdminRequisite, getMixins, getApiGenerator } from 'plain-kit'
// 全局注册 TimeRangePicker、AuthButton、Pagination、Selector、FormItemTip、FormDialog、Tag 等后台必备组件
Vue.use(AdminRequisite, {
AuthButton: {
// 可以在这里做全局配置
}
})
let mixins = getMixins()
// 对mixins进行扩充
/*
import { mapGetters } from 'vuex'
mixins = {
...mixins,
computed: {
...mixins.computed,
...mapGetters([
'dict',
]),
}
}
*/
const apiGenerator = getApiGenerator({ request })
export { mixins, apiGenerator }
somepage.vue
import { mixins, apiGenerator } from '@/main'
export default {
mixins: [mixins],
data () {
return {
api: apiGenerator('/somepage')
}
}
}
Usage
mixins
页面公共逻辑混入:
增查改删
常用dayjs插件
常用过滤器
常用校验
必备弹框
常用函数
页面销毁时终止尚未完成的查询请求(列表查询和单条查询)
单条删除时,如果删除的是当前页(非第一页)的最后一条,会将页码修改为上一页
...
全局配置默认值:
getMixins({
// dayjs插件注册 已默认注册常用的
dayjsExtends: ['isBetween', 'isSameOrAfter', 'isSameOrBefore', 'isToday', 'isTomorrow', 'isYesterday', 'objectSupport', 'relativeTime', 'minMax'],
// 接口参数、返回值格式定制化
normalizer: {
// [列表查询接口]页码字段名
pageNo: 'pageNo',
// [列表查询接口]页容量字段名
pageSize: 'pageSize',
// [列表查询接口]返回值中列表字段所在位置
// 考虑到分页与不分页的返回格式可能是不同的 所以支持传入一个数组 数组会被遍历 直到找到为止
list: ['data', 'data.records'],
// [列表查询接口] 返回值中总记录数字段所在位置
total: 'data.total',
// [0]指定列表查询返回值中单条的主键
// [1]指定单条查询接口参数的主键
// [2]指定单条查询接口返回值中数据所在位置
row: ['id', 'id', 'data']
}
})
配置方式:与默认值进行混入
normalizer具体配置方式请查看getPropByPath用法
normalizer支持针对某个页面进行单独配置:
export default {
data () {
return {
normalizer__: {}
}
}
}
getMixins()为你注册了一些常用的全局方法
- this._: lodash
- this.$dayjs: dayjs
- 为什么不选用momentjs?
- momentjs已官宣停止开发进入维护状态,并建议使用其他库
- dayjs和momentjs的api一致,但体积小得多
- 为什么不选用momentjs?
- this.$isEmpty: 判空
- this.$notEmpty: 判非空
- this.$typeOf: 获取变量精确类型
- 弹框相关 → Swal
钩子函数
dataGetter__(afterRetrieve, beforeRetrieve)
afterRetrieve
查询单条记录之后
参数:查询单条记录的返回值
你可以在这个钩子中修改单条查询接口的返回值
beforeRetrieve
查询单条记录之前
<FormDialog :dataGetter="() => dataGetter__( resData => { // 在查询单条记录之后做点什么... // 比如将返回值中status的值修改为1: // 同步修改: resData.status = 1 // 异步修改: this.$POST().then(res => { this.row__.data.status = 1 }) }, () => { // 在查询单条记录之前做点什么... } )" />
submit__(paramHandler)
执行增删改(提交表单)时
比如你想在新增时加一个参数:
<FormDialog :submit="() => submit__( // 参数可以是一个函数或一个对象 // 函数会在表单校验通过后、接口调用前执行,对象会被用作接口参数 () => { // 在提交之前做点什么... if (dialogStatus__ === 'c') { row__.data.status = 1 } }).then(() => { // 在提交之后做点什么... }).catch(() => { return { close: false } }) " />
this.onQueryChange__(valid)
列表筛选参数改变后(做了500毫秒的节流处理)
valid: 校验是否通过
dialogStatus__
当前的表单状态(string)
可能的值:'c'(新增) / 'r'(查看) / 'u'(编辑) / ''(关闭)
默认/初始值定义
data () {
return {
// 表单绑定对象
row__: {
data: {
arr: [],
num: 100
}
},
// 列表查询参数
list__: {
query: {
pageSize: 15, //覆盖默认值10
status: 1 //新增的
}
}
}
}
this.getList__()
刷新列表
init__
在页面初始化、查询参数改变、单条增删查改时getList__会被调用
你可以在methods中定义一个init__方法来取代getList__
methods: {
init__(intention, res)
{
// intention可能的值:'init' 'pageNoChange' 'queryChange' 'c' 'r' 'u' 'd' 'enable' 'disable'
// res:'c' 'r' 'u' 'd' 'enable' 'disable' 时的接口返回值
// 在获取列表之前搞点事情...
this.getList__(res => {
// 在获取列表之后搞点事情...
// res为列表接口返回值
})
}
}
filters(所有过滤器均可当作方法调用)
id2name__
数据字典转义
<el-table-column> <template slot-scope="{row}"> {{row.type | id2name__(dict.type)}} </template> </el-table-column>
当作方法调用:
/** * @param {String|Symbol} 需要查询的id * @param {Array} 由多个```{[id]: '', [name]: ''}```构成的数组 * @param {String} 自定义id和name对应的属性名 默认为'dataValue/dataName' * @return {Any} id对应的name */ this.id2name__('1', [ { dataValue:'1', dataName: 'a' }, { dataValue:'2', dataName: 'b' }, ]) // 'a' this.id2name__('1', [ { id:'1', name: 'a' }, { id:'2', name: 'b' }, ], 'id/name') // 'a'
required__: 必填
phone__: 手机
idCard__: 身份证
email__: 邮件
account__: 账号
pwd__: 密码
version__: 版本号
len__: 字符长度限制 参数均为Number类型
len__( Number, // 长度上限 [Number] // 长度下限 )
tel__(): 座机
允许多个:tel__()
仅能单个:tel__(false)
coord__(): 坐标
经度:coord__('lng')
纬度:coord__('lat')
integer__: 整数
integer__({ required: Boolean, // 是否必填 默认false min: Number, // 最小值(≥) greaterThan: Number, // 需大于(>) max: Number, // 最大值(≤) lessThan: Number, // 需小于(<) maxLen: Number, // 最大长度(≤) minLen: Number, // 最小长度(≥) len: Number, // 长度(=) })
decimal__(): 数字
decimal__({ required: Boolean, // 是否必填 默认false allowInt: Boolean, // 是否允许整数 默认true min: Number, // 最小值(≥) greaterThan: Number, // 需大于(>) max: Number, // 最大值(≤) lessThan: Number, // 需小于(<) decimalPlaces: Number, // 小数位长度(=) minDecimalPlaces: Number, // 小数位长度下限(≥) maxDecimalPlaces: Number // 小数位长度上限(≤) })
api生成器(根据接口前缀自动生成增删查改接口)
缩写说明:crud分别表示增查改删
getApiGenerator
getApiGenerator({
// axios封装 默认为空 必传
request,
// 接口后缀默认值
url: {
c: 'create', // 单条新增
r: 'queryForDetail', // 单条查询
u: 'update', // 单条编辑
d: 'delete', // 单条删除
list: 'queryForPage', // 列表查询
updateStatus: 'updateStatus', // 单条状态变更
},
// 请求方式 默认全POST
method: {
c: 'POST',
r: 'POST',
u: 'POST',
d: 'POST',
list: 'POST',
updateStatus: 'POST',
},
// 提交方式 默认空数组(全json) 可以在这里指定接口使用formData
formData: ['c', 'u'],
// 使用config你可以完全自定义每个接口的请求配置 甚至支持function(从而能够拿到data)
config: {
c: {},
r (data) {
return {}
},
}
})
如果某个接口的前缀不是somepage,可以在后缀前添加斜线
data () {
return {
api: apiGenerator('/somepage', {
url: {
r: '/anotherpage/selectOne',
},
})
}
}
这样会得到:
- /somepage/create
- /somepage/update
- /somepage/delete
- /somepage/queryForPage
- /somepage/updateStatus
- /anotherpage/selectOne
如果不需要单条查询接口,想直接使用列表的数据
data () {
return {
api: apiGenerator('/somepage', {
url: {
r: false,
},
})
}
}
以上配置均支持全局统一配置(main.js)
getApiGenerator({
url: {
...
},
method: {
...
}
})
如果你的接口是动态拼接式的(RESTful风格),或者参数名不统一,可以自定义接口地址和参数:
api: apiGenerator('/somepage', {
// 方式1
url: {
r: data => 'module/' + data.id,
},
// 方式2
config: {
r (data) {
return {
url: 'module/' + data.id
}
},
}
})
将你传入的request绑定到了Vue原型上:
this.$request(config)
为方便起见,为所有支持的请求方法提供了别名:
post请求示例:
this.$POST(url, data?, config?)
支持$GET / $POST / $PATCH / $PUT / $DELETE / $HEAD
为避免重名 采用全大写
屏蔽了get和post请求参数属性不一致的差异($request不变)
过滤掉参数中部分值为falsy值(null/NaN/undefined)的属性
有时候参数所绑定的对象中会存在一些临时属性 而这些属性是不应该提交到后端的 我们约定这些临时变量以双下划线__开头 __开头的属性会被过滤掉
下载
ajax请求方式下载
this.$download(url, data, { method: '', // 必传 ... })
地址栏请求方式下载
this.$download(url, data?, config?)
上传(请求体为multipart/form-data类型)
this.$upload(url, data?, config?)
默认POST请求
给$download/$upload添加全局回调
由于$download/$upload本质上还是调用你的request 所以在request的响应拦截器中判断即可
request.interceptors.response.use(
response => {
// $download
if (response.config.responseType === 'blob') {
succeed({
titleText: '导出成功',
timer: 5000
})
}
},
)
qs
this.$qs
趁手小型组件
SvgIcon
$ npm i svg-sprite-loader svgo --dev
- vue.config.js
chainWebpack: config => {
config.module
.rule('svg')
.exclude.add(resolve('src/assets/svg-sprite'))
.end()
config.module
.rule('svg-sprite')
.test(/\.svg$/)
.include.add(resolve('src/assets/svg-sprite'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
- main.js
import { SvgIcon } from 'plain-kit'
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(require.context('@/assets/svg-sprite', false, /\.svg$/))
Vue.component('SvgIcon', SvgIcon)
<SvgIcon icon-class=""/>
QR / 二维码 支持蒙层
import { QR } from 'plain-kit'
components: { QR }
<QR :value=""/>
如果value的值比较小 而size的值比较大 会导致图片模糊 此时可以增大scale解决:
<QR :value="" :options="{scale:25}"/>
scale指二维码每个黑点占用的px数量 可选值为二次方数值 如25 36 49 64 81
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 二维码字符串(如果为base64编码 则不经过转换直接展示) | String | ||
mask-text | 蒙层文案 | String | ||
size | 宽高(单位px) | String | 200 | |
options | 底层依赖qrcode的参数 | Object | https:// github.com/soldair/node-qrcode | {margin:0, scale:16, errorCorrectionLevel:'L'} |
事件名称 | 说明 | 回调参数 |
---|---|---|
load | 加载完成后触发 | |
error | 加载出错后触发 | event |
AuthButton / 权限按钮
import { AuthButton } from 'plain-kit'
// 全局注册(未注册AdminRequisite时)
Vue.use(AuthButton, {
// 全局配置
})
// 局部注册
components: {
AuthButton
}
Attribute | Description | Configuration Mode | Type | Default |
---|---|---|---|---|
name | 文案 | local | string | |
show | 是否显示 | local, global | boolean, function | false |
catalog | 目录 | global | object | |
elPopconfirmProps | el-popconfirm的配置 未配置时默认不开启popconfirm | local, global | object | |
elTooltipProps | el-tooltip的配置 默认circle为true时开启tooltip | local, global | object |
...以及el-button所有props
show
show为function时支持返回boolean或者返回promise在promise内resolve一个boolean
catalog
如果同一个name的AuthButton需要多处使用 你可以在catalog中针对这个name进行全局配置(混入)
elPopconfirmProps、elTooltipProps也支持在catalog中使用
默认值:
{
新增: {
type: 'primary',
icon: 'el-icon-circle-plus-outline'
},
查看: {
icon: 'el-icon-search',
circle: true
},
编辑: {
type: 'primary',
icon: 'el-icon-edit',
circle: true
},
删除: {
type: 'danger',
icon: 'el-icon-delete',
circle: true,
elPopconfirmProps: {}
},
停用: {
type: 'warning',
icon: 'el-icon-video-pause',
circle: true,
elPopconfirmProps: {}
},
启用: {
type: 'success',
icon: 'el-icon-video-play',
circle: true,
elPopconfirmProps: {}
},
}
- 使用在catalog中定义过的AuthButton
<AuthButton @click="" name="编辑"/>
- 未在catalog中定义的AuthButton
<AuthButton @click="" name="" circle type="primary">
<i class="el-icon-finished"/>
</AuthButton>
Selector / 下拉框选择器
import { Selector } from 'plain-kit'
已在AdminRequisite中全局注册
<Selector v-model="list__.query.status"
:options="['停用', '启用']"
placeholder="状态"
/>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
v-model / value | 绑定值 | |||
options | 选项 | Array | ||
optionKey | options的key和label 用斜线分隔(options的元素为Object类型时有效) | String | dataValue/dataName | |
rightLabel | 浮动在右侧的label属性名(options的元素为Object类型时有效) | String | ||
ellipsis | 是否限宽并对超长的label作溢出省略处理(默认是超长撑开) | Boolean | false | |
search | 搜索方法(即el-select的remote-method) | Function |
支持el-select全部参数(remote-method和value-key除外)
optionKey:
格式为key/label/rightLabel? 其中label支持模板字符串格式 如id/${startTime}-${endTime}
Pagination / 分页
import { Pagination } from 'plain-kit'
已在AdminRequisite中全局注册
支持el-pagination所有参数和事件
FormItemTip / 表单项提示
用于表单项的填写规则说明
import { FormItemTip } from 'plain-kit'
已在AdminRequisite中全局注册
<el-form-item>
<el-input/>
<form-item-tip>xxx</form-item-tip>
</el-form-item>
OnefoldTable / 一维表格
import { OnefoldTable } from 'plain-kit'
components: { OnefoldTable }
<OnefoldTable title="标题">
<tr>
<td>xxx</td>
<td>xxx</td>
</tr>
<tr>
<td>xxx</td>
<td>xxx</td>
<td>xxx</td>
<td>xxx</td>
</tr>
</OnefoldTable>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
title | 标题 | String |
CheckAllBox / 支持全选的复选框
import { CheckAllBox } from 'plain-kit'
components: { CheckAllBox }
<CheckAllBox v-model="date" :options="{
周一: 1,
周二: 2
}"/>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
v-model / value | 绑定值 | String / Number / Boolean | ||
options | 选项 key即label value即value | Object |
支持el-checkbox全部参数
AuthTree / 权限编辑树
import { AuthTree } from 'plain-kit'
components: { AuthTree }
<AuthTree v-model="authTree"/>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
v-model / value | 绑定值 | Array |
支持el-checkbox全部参数
SmsButton / 短信验证码按钮
import { SmsButton } from 'plain-kit'
components: { SmsButton }
// 如果发送短信前需要先校验手机号
methods: {
sms(e)
{
this.$refs.formDialog.$refs.elForm.validateField('SmsButton', err => {
if (err) {
// 不开始计时
e.stopPropagation()
} else {
// 调用短信接口
}
})
}
}
<SmsButton @click="sms($event)"/>
事件名称 | 说明 | 回调参数 |
---|---|---|
click | 点击后触发(返回值需为Promise类型) |
AudioPlayer / 音乐播放器(原生audio元素封装)
import { AudioPlayer } from 'plain-kit'
components: { AudioPlayer }
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
show.sync | 是否开启 | Boolean | false | |
src | 音频文件链接 | String | ||
*inline | 以行内元素的方式显示 | Boolean | false |
支持audio标签全部参数
inline
- 默认false表示以弹框形式显示
- 开启后不再需要show参数
VideoPlayer / 视频播放器(原生video元素封装)
import { VideoPlayer } from 'plain-kit'
components: { VideoPlayer }
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
show.sync | 是否开启 | Boolean | false | |
src | 视频文件链接 | String | ||
poster | 视频封面图片链接 | String | ||
inline | 以行内元素的方式显示 | Boolean | see below | false |
支持video标签全部参数
inline
- 默认false表示以弹框形式显示
- 开启后不再需要show参数
Tag / 标签(el-tag封装)
使用场景:在预设的范围中根据某个动态的值显示其对应的标签
import { Tag } from 'plain-kit'
components: { Tag }
已在AdminRequisite中全局注册
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
value | 值 | any | ||
options | 选项 | string, array | see below |
options
预设值:
- 'whether':是/否
- 'being':有/无
- 'status':启用/停用
- 'required':需要/不需要
- 'auth':已授权/未授权
<Tag :value="value" options="whether"/>
支持自定义
<Tag :value="0" :options="[
{
value: 0, // 支持数组 数组以是否包含作为判断依据
text: '0对应文案', // 即el-tag的innerText
type: 'danger' // 即el-tag的type
},
{
value: 1,
text: '1对应文案',
type: 'warning'
},
]"/>
FormDialog / 表单对话框
Features
- 支持el-dialog几乎所有参数、事件和slot
- 支持el-form几乎所有参数、事件(el-form没有slot)
import { FormDialog } from 'plain-kit'
已在AdminRequisite中全局注册
<FormDialog
:show.sync="show"
:dataGetter="dataGetter"
:submit="submit"
title=""
v-model="form"
>
<template #el-form>
<el-form-item prop="input">
<el-input v-model="form.input"/>
</el-form-item>
</template>
</FormDialog>
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
show.sync | 是否开启 | boolean | false | |
title | 对话框标题 | string | ||
readonly | 是否只读 | boolean | false | |
v-model | 表单数据对象(即el-form的model参数) | any | see below | {} |
elFormProps | el-form参数对象 | object | el-form绝大部分参数 | {} |
dataGetter | 获取数据方法(返回值需为Promise类型) | function | ||
submit | 提交方法 | Function | ||
... | el-dialog参数 | - | https://element.eleme.cn/#/zh-CN/component/dialog |
name | description |
---|---|
el-form | el-form |
title | el-dialog的slot |
footer | el-dialog的slot |
el-form插槽不是必须的 你可以传任意slot进去 只是提交时不会帮你校验罢了 你可以自行校验
v-model
即使不使用el-form插槽 也建议传入 表单关闭时会将数据对象重置为初始状态(以避免二次打开时显示上次value)
dataGetter
获取数据前后、提交前后的生命周期都是暴露出来的 如下所示
dataGetter()
{
// 表格打开之后、获取数据之前
return request().then(() => {
// 获取数据之后
})
}
submit
submit()
{
// 提交之前
if (true) { //校验通过
return this.$POST('').then(() => {
// 提交之后
})
} else {
this.$warn('校验失败')
}
}
submit的返回值如果是一个Promise 则then时默认关闭弹框 而reject时不关闭
注意:如果catch了reject 则reject时也会关闭弹框 这是因为组件内部已无法获知被你捕获的reject
你可以在最后一个then/catch中
return { close: false }
来控制是否关闭弹框
submit没有返回值或者返回值不是Promise时 则submit执行完毕后默认关闭弹框 你可以
return { close: false }
来控制该行为
内部el-form的ref获取方式:
先给FormDialog添加一个ref 比如formDialog
this.$refs.formDialog.$refs.elForm
footer slot 示例
<FormDialog
:show.sync="form.show"
ref="formDialog"
>
<div slot="footer" class="footer">
<el-button
type="primary"
:loading="$refs.formDialog && $refs.formDialog.submitting"
@click="() => { $refs.makeOutFormDialog.doSubmit() }"
>
提 交
</el-button>
<el-button @click="() => { form.show = false }">
取 消
</el-button>
</div>
</FormDialog>
Swal / alert封装(基于sweetalert2)
- this.$succeed
- this.$notice
- this.$warn
- this.$err
- this.$confirmation
- this.$Swal
import { Swal } from 'plain-kit'
// 原型挂载(未注册AdminRequisite时)
Vue.use(Swal)
this.$succeed('成功弹框')
.then(() => {
// 关闭时
})
this.$notice('提示弹框')
.then(() => {
// 关闭时
})
this.$warn('警告弹框')
.then(() => {
// 关闭时
})
this.$err('错误弹框')
.then(() => {
// 关闭时
})
this.$confirmation('确认弹框')
.then(e => {
// 点击确认
})
.catch(e => {
if (e.isDenied) {
// 点击拒绝
} else if (e.isDismissed) {
// 点击取消
}
})
// 单独使用
Swal.succeed()
Swal.notice()
Swal.warn()
Swal.err()
Swal.confirmation()
// 强制确认
// 强制状态下无法取消(无取消按钮、点击弹框外部、按下esc键均无效果)
Swal.confirmation('同意以继续', true)
// 简单表单 + 三个按钮 + 异步确认的例子
Swal.confirmation({
input: 'text',
inputAttributes: {
placeholder: '备注'
},
confirmButtonText: `同意`,
showLoaderOnConfirm: true,
preConfirm: input => {
return new Promise(resolve => {
setTimeout(resolve, 500)
}).then(() => {
alert('同意成功')
}).catch(e => {
alert('同意失败')
})
},
// 拒绝按钮
showDenyButton: true,
denyButtonText: `拒绝`,
returnInputValueOnDeny: true,
preDeny: input => {
if (input) {
return new Promise((resolve, reject) => {
setTimeout(reject, 500)
}).then(() => {
alert('拒绝成功')
}).catch(e => {
alert('拒绝失败')
})
} else {
this.$Swal.showValidationMessage(`请填写备注`)
return false
}
},
}).then(e => {
alert('同意')
}).catch(e => {
if (e.isDenied) {
alert('拒绝')
} else if (e.isDismissed) {
alert('取消')
}
})
Swal只是对最常用的五种场景做了封装 支持只传字符串作为title
完整配置参阅 https://sweetalert2.github.io/
PullToRefresh / 下拉刷新上拉加载
<PullToRefresh
v-model="list"
:listGetter="()=>$http.post('', query)"
:param="query"
>
<van-cell v-for="item in list" :key="item" :title="item"/>
</PullToRefresh>
Props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
v-model | 双绑 | Array | [] | |
listGetter | 列表接口(返回值需为Promise类型) | Function | ||
param | 接口参数对象 | Object | ||
normalizer | 接口参数/返回值格式定制 | Object | *见下方说明 | |
vanPullRefreshProps | van-pull-refresh参数(混入) | Object | ||
vanListProps | van-list参数(混入) | Object | {finishedText: '没有更多了', immediateCheck: true} |
Slots
名称 | 说明 | SlotProps |
---|---|---|
empty | 加载完成后数据为空的dom |
支持van-pull-refresh所有具名插槽
支持van-list所有具名插槽
注意:由于van-pull-refresh和van-list都有名为loading的插槽 所以你传入的loading插槽会被两者共用
normalizer
默认值:
{
// 接口参数中页码的字段名
"pageNo": "pageNo",
// 接口返回值中数组的字段路径
"list": "data.list",
// 判断是否为最后一页
"isLastPage": res => res.data && !res.data.hasNextPage
}
配置方式:与默认值进行混入
工具函数
getEnv / 获取运行环境(主要用于h5)
import { getEnv } from 'plain-kit'
目前有三种可能的返回值(Promise类型)
- mp(小程序)
- wechat(微信内置浏览器)
- browser(其他浏览器)
parseQueryString / 获取当前url某个查询参数的值
import { parseQueryString } from 'plain-kit'
const code = parseQueryString('code')
//or
const { code } = parseQueryString()
/**
* 获取当前url某个查询参数的值
* 支持微信公众号授权特例:授权后会重定向回来并在链接中加入一个code参数 但微信没有考虑hash路由的情况 所以获取这个code需要特殊处理
* @param {Object}
* {String} key - 查询参数的key 如果为空 则返回查询参数映射的对象 可以解构使用
* {String} mode - router模式 可选值'history'/'hash' 默认'hash'
* {Boolean} del - 是否在url中删除该值(删除会引发页面刷新)
* @return {String|Object} 查询参数中key对应的value / 如果key为空 则返回查询参数整个对象
*/
注意:如果search和hash中同时包含code 如http://localhost:8080/?code=1#/?code=2
取的是search中的code 即返回1
dynamicallyLoadScript / 动态加载js
import { dynamicallyLoadScript } from 'plain-kit'
dynamicallyLoadScript(src)
/**
* @param {String} src - 脚本url
* @return {Promise}
*/
highlightFormError / 高亮提示校验失败的表单项
import { highlightFormError } from 'plain-kit'
平滑滚动至校验失败的第一个表单项、并对所有校验失败的表单项产生震动效果
FormDialog组件已内置 可用于其他的el-form
getPropByPath / 支持多层的属性访问
import { getPropByPath } from 'plain-kit'
const obj = {
a: {
b: 'c'
}
}
getPropByPath(obj, 'a.b') // 'c'
getPropByPath(obj) // 返回obj本身
/**
* @param {Object} 对象
* @param {String} 属性名 支持点运算符获取深层属性 可选
* @return {Any} 属性值 如果第二个参数为空 则返回对象本身
*/
validator / 输入校验
import { validator } from 'plain-kit'
const { idCard } = validator
const errMsg = idCard.validator('xxx')
if (errMsg) {
Toast(errMsg) // '格式不正确'
return
}
/**
* @param {String} 需要校验的内容
* @return {String} 校验失败提示信息 如果校验通过则返回''
*/
前文提到的输入校验都可以像这样独立使用 不过:
不再需要后面的双下划线 这里不需要规避命名冲突
需要多点一层validator 这也是为了兼容element所做的妥协
该方法不是通过true和false来标识校验是否通过 因为错误往往需要一个友好的原因提示
如果仅仅想知道是否校验通过:
!idCard.validator('xxx') // true通过 false失败
isEllipsis / 判断dom是否触发溢出省略(text-overflow: ellipsis)
import { isEllipsis } from 'plain-kit'
/**
* @param {Element} 需要判断的元素
* @return {Boolean} 是否触发溢出省略
*/
isEllipsis(document.querySelector('.text'))
typeOf / 获取变量的精确类型
动机:原生js的typeof等类型检测手段都存在各种缺陷
import { typeOf } from 'plain-kit'
/**
* @param {any} 需要判断的变量
* @return {string} 变量类型(全小写) 如string null undefined file...
*/
typeOf(1) // 'number'
isBase64 / 判断是否为base64编码字符串
import { isBase64 } from 'plain-kit'
/**
* @param {string} 需要判断的字符串
* @param {object}
* {string} mediaType - 媒体类型 可选值参考 https://en.wikipedia.org/wiki/Data_URI_scheme
* {boolean} scheme - 是否包含前缀 默认true
* @return {boolean} 结果
*/
isBase64(1, {
mediaType: 'image',
scheme: false
}) // false
isEmpty & notEmpty / 判空 & 判非空
notEmpty() 等同于 !isEmpty()
notEmpty作用:可读性更高
import { isEmpty, notEmpty } from 'plain-kit'
/**
* @param {any} 需要判断的变量
* @return {boolean} 结果
*/
isEmpty(0) // false
isEmpty({}) // true
isEmpty([]) // true
jsonToFormData / json转formData
import { jsonToFormData } from 'plain-kit'
/**
* @param {object} 需要转换的对象
* @return {formData} 结果
*/