unv-ui v0.1.14
unv-ui
Introduce
unv-ui并不是一个严格意义上的UI组件库,它更像是一个工具库。它也包含一些公共的指令,比如v-form。
它的很多组件实际上并没有任何样式,比如UvSelect、UvArea只是做了数据的兼容层。
为什么要做数据兼容层组件,而不是做一个带有UI样式的完全体组件?
因为在很多toc的页面中,UI的样式是要靠自己实现的,但是很多通用的功能写到具体的组件中难以维护。
比如我想要一个省市区选择器:它可以是弹窗形式,也可以是并列三连的选择器,也可以是级联选择器。从功能上讲他们都是省市区选择器,然而他们的UI是不同的,开发者在组织代码时可能会出现areaV1.vue、areaV2.vue、areaV3.vue,但是他们的逻辑是相通的。数据兼容层组件可以让开发者更专注于实现组件的视图部分。
Links
Requirements
| Minimum | |
|---|---|
| Vue | 2.6.14 |
Install
npm install unv-uiQuick Start
import Vue from 'vue'
import UnvUi from 'unv-ui'
Vue.use(UnvUi)Docs
UvArea
省市区选择器,数据兼容层,你可以使用任意基于v-model的选择器组件传入到具名插槽中。
当省切换时,你不再需要组织代码来重置市 区的选择结果和对应的选项数组。UvArea会帮你做这些事。
你只需要关注省市区单个选择器组件的实现。
UvArea只做数据层兼容,你可以使用任何组件选择器来配合UvArea(比如el-select、a-select或自己实现的选择器)。
UvArea的行政区划数据来自@/vant/area-data。
Usage
<template>
<UvArea v-model="pca">
<template #province="{ options }">
<el-select v-model="pca.p">
<el-option v-for="{ text, value } in options" :key="value" :label="text" :value="value"> </el-option>
</el-select>
</template>
<template #city="{ options }">
<el-select v-model="pca.c">
<el-option v-for="{ text, value } in options" :key="value" :label="text" :value="value"> </el-option>
</el-select>
</template>
<template #area="{ options }">
<el-select v-model="pca.a">
<el-option v-for="{ text, value } in options" :key="value" :label="text" :value="value"> </el-option>
</el-select>
</template>
</UvArea>
</template>
<script>
export default {
name: 'UseArea',
data() {
return {
pca: {
p: '',
c: '',
a: '',
},
};
},
};
</script>UvArea Slot
| name | 说明 | 参数 |
|---|---|---|
| province | 省 | {options} |
| city | 市 | {options} |
| area | 区 | {options} |
todo
- 行政区划源数据支持自定义
- 指定选项的值为选项对象的某个属性值
UvSelect
选择器,数据兼容层。
你不再需要组织单选、多选的功能代码,也不需要关注选中结果的收集,UvSelect会帮你做这些事。
你只需要专注option选项组件的实现。
Usage
<template>
<div>
<!-- e.g.1 -->
<div>{{ selectedValue }}</div>
<UvSelect v-model="selectedValue">
<SelectOption1 v-for="item in tableData" :key="item.id" :value="item.id" v-bind="item"></SelectOption1>
</UvSelect>
<!-- e.g.2 -->
<div>{{ selectedValue2 }}</div>
<UvSelect v-model="selectedValue2" multiple>
<SelectOption2 v-for="item in tableData" :key="item.id" :value="item.id" v-bind="item"></SelectOption2>
</UvSelect>
</div>
</template>
<script>
import SelectOption1 from './SelectOption1.vue';
import SelectOption2 from './SelectOption2.vue';
export default {
components: {
SelectOption1,
SelectOption2,
},
data() {
return {
selectedValue: '',
selectedValue2: '',
tableData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
},
{
id: 2,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄',
},
{
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
},
],
};
},
};
</script>SelectOption1
注意inject
<template>
<div class="item" @click="selectAddress" :class="{ active }">
<div>{{ date }}</div>
<div>{{ name }}</div>
<div>{{ address }}</div>
</div>
</template>
<script>
export default {
name: 'SelectOption1',
inheritAttrs: false,
inject: ['$Selector'],
props: {
value: [String, Number],
data: Array,
date: {},
name: {},
address: {},
},
computed: {
active() {
return this.$Selector.calcOptActive(this.value);
},
},
methods: {
selectAddress() {
this.$Selector.optSelect({ value: this.value });
},
},
};
</script>
<style lang="scss" scoped>
.item {
border: 1px dashed #d9d9d9;
border-radius: 2px;
width: 178px;
height: 178px;
border-radius: 6px;
margin-left: 6px;
&.active {
background-color: #409eff;
}
}
</style>Select Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| value/v-model | 绑定值,必填 | string/number/Array | ||
| multiple | 多选 | boolean | false | |
| tag | 自定义标签 | string | div |
Select Provide
| 参数 | 说明 |
|---|---|
| $Selector | UvSelect实例对象 |
Select Methods
| 参数 | 说明 | |
|---|---|---|
| optSelect | 用于修改UvSelect的值。如果multiple为true,既能用来选中也能用来取消选中某个option | {value:'xx'} |
| calcOptActive | 用于表示当前option的值是否被选中 | value |
computed: {
active() {
return this.$Selector.calcOptActive(this.value);
},
},
methods: {
curOptionSelect() {
this.$Selector.optSelect({ value: this.value });
},
},UvDialog
函数式弹窗,将Vue组件赋值给参数view,调用show可以拉起一个弹窗,弹窗的内容是view传入的Vue组件内容。
组织弹窗功能时,你不再需要导入一个弹窗.vue组件,在components声明然后再在template模板中使用<弹窗></弹窗>;更不需要声明一个isShow来控制弹窗的开关。
你只需要专注弹窗的内容组件实现即可,这使我们的业务代码的内聚性更高。
Usage
<template>
<div>
<div><button @click="showDialog">showDialog</button></div>
</div>
</template>
<script>
import dialogContent from "./cmp/dialogContent.vue"
export default {
name: "dialogtest",
methods: {
showDialog() {
const $UvDialog = this.$UvDialog
// 或 new UvDialog
new $UvDialog(
{
view: dialogContent,
router: this.$router,
store: this.$store
},
{
originPage: "dialogTest",
onConfirm: (data) => {
console.log("onConfirm", data)
}
}
).show()
}
}
}
</script>dialogContent
<template>
<div class="dialog-content">
<div>{{ originPage }}</div>
<div>
<div>{{ msg }}</div>
<el-input v-model="msg" placeholder="请输入内容"></el-input>
<div style="text-align: right">
<el-button type="primary" @click="printRoute"> 输出$route $store </el-button>
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="confirm">确认</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: "dialogContent",
data() {
return {
msg: "123"
}
},
methods: {
close() {
this.$emit("hide")
},
printRoute() {
console.log(this.$route)
console.log(this.$router)
console.log(this.$store)
},
confirm() {
this.onConfirm && this.onConfirm(this.msg)
this.close()
}
}
}
</script>
<style>
.dialog-content {
width: 500px;
height: 300px;
background: white;
}
</style>Parameter Type
new UvDialog({view,router,store},cfg)| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| view | 弹窗的内容组件 | VueComponent | |
| router | 路由器,如果你需要在view中访问路由,那么该参数必填,router:this.$router | VueRouter | |
| store | 状态管理器,如果你需要在view中访问Vuex的状态,那么该参数必填,store:this.$store | Store | |
| cfg | 额外的参数,这相当于给view组件加一个mixin,你可以在view组件中通过this访问到cfg的内容,通常用来传递回调事件或者传入初始参数。 | Any |
todo
- 支持挂载到指定的DOM,而不是只挂载
document.body - show支持promise
- 略去router和store配置
UvCountDown
倒计时,基于requestAnimation。
Usage
<template>
<div>
<el-button type="primary" @click="flag = !flag">toggle</el-button>
<UvCountDown :value="futureDeadline" v-if="flag">
<template #default="{ d, h, m, s }">
{{ d }}
{{ h }}
{{ m }}
{{ s }}
</template>
</UvCountDown>
<keepAlive>
<UvCountDown :value="lastDeadline" v-if="flag">
<template #default="{ d, h, m, s }">
{{ d }}
{{ h }}
{{ m }}
{{ s }}
</template>
</UvCountDown>
</keepAlive>
</div>
</template>
<script>
export default {
data() {
return {
futureDeadline: Date.now() + 1000 * 60 * 70,
lastDeadline: Date.now() - 1000 * 60 * 60,
flag: true
}
}
}
</script>CountDown Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| value | 确定的时间点,必填,支持Date对象/毫秒数/YYYY-MM-DD hh:mm:ss三种格式 | Date/Number/String | ||
| timeIndices | 是否开启倒计时功能 | Boolean | true/false | true |
| tag | 自定义标签 | string | div |
CountDown Event
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| start | 开始倒计时,在mounted、activated阶段触发 | |
| pause | 暂停倒计时,在deactivated、beforeDestroy阶段触发 | |
| end | 倒计时结束,达到目标时间 |
CountDown Methods
| 参数 | 说明 | |
|---|---|---|
| startCountDown | 开始倒计时 | |
| pauseCountDown | 暂停倒计时 |
CountDown Slot
| name | 说明 | 参数 |
|---|---|---|
| - | 用于向视图传递数据的插槽,d-h-m-s分别表示日-时-分-秒 | { d, h, m, s } |
todo
- 目前修改value的值会让暂停状态下的CountDown启动倒计时,这或许是个bug
todo
- v-form
- changelog