提交 81d683f0 编写于 作者: study夏羽's avatar study夏羽

更新依赖插件

上级 5748d504
......@@ -2,3 +2,4 @@
/node_modules/
/unpackage/
/vue.config.js
/manifest.json
......@@ -182,7 +182,25 @@
"enablePullDownRefresh": false
}
}
],
,{
"path": "uni_modules/uni-upgrade-center/pages/version/list",
"style": {
"navigationBarTitleText": "版本列表"
}
}
,{
"path": "uni_modules/uni-upgrade-center/pages/version/add",
"style": {
"navigationBarTitleText": "新版发布"
}
}
,{
"path": "uni_modules/uni-upgrade-center/pages/version/detail",
"style": {
"navigationBarTitleText": "版本信息查看"
}
}
],
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#1296db",
......
## 1.2.1(2022-09-05)
- 修复 当 text 超过 max-num 时,badge 的宽度计算是根据 text 的长度计算,更改为 css 计算实际展示宽度,详见:[https://ask.dcloud.net.cn/question/150473](https://ask.dcloud.net.cn/question/150473)
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-badge](https://uniapp.dcloud.io/component/uniui/uni-badge)
## 1.1.7(2021-11-08)
- 优化 升级ui
- 修改 size 属性默认值调整为 small
- 修改 type 属性,默认值调整为 error,info 替换 default
## 1.1.6(2021-09-22)
- 修复 在字节小程序上样式不生效的 bug
## 1.1.5(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.4(2021-07-29)
- 修复 去掉 nvue 不支持css 的 align-self 属性,nvue 下不暂支持 absolute 属性
## 1.1.3(2021-06-24)
......
<template>
<view class="uni-badge--x">
<slot />
<text v-if="text" :class="classNames" :style="[badgeWidth, positionStyle, customStyle, dotStyle]"
class="uni-badge"
@click="onClick()">{{displayValue}}</text>
<text v-if="text" :class="classNames" :style="[positionStyle, customStyle, dotStyle]"
class="uni-badge" @click="onClick()">{{displayValue}}</text>
</view>
</template>
......@@ -13,25 +12,33 @@
* @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容
* @property {String} type = [default|primary|success|warning|error] 颜色类型
* @value default 灰色
* @property {String} size = [normal|small] 角标内容
* @property {String} type = [info|primary|success|warning|error] 颜色类型
* @value info 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {String} size = [normal|small] Badge 大小
* @value normal 一般尺寸
* @value small 小尺寸
* @property {String} inverted = [true|false] 是否无需背景颜色
* @property {Number} maxNum 展示封顶的数字值,超过 99 显示 99+
* @property {String} absolute = [rightTop|rightBottom|leftBottom|leftTop] 开启绝对定位, 角标将定位到其包裹的标签的四角上
* @value rightTop 右上
* @value rightBottom 右下
* @value leftTop 左上
* @value leftBottom 左下
* @property {Array[number]} offset 距定位角中心点的偏移量,只有存在 absolute 属性时有效,例如:[-10, -10] 表示向外偏移 10px,[10, 10] 表示向 absolute 指定的内偏移 10px
* @property {String} isDot = [true|false] 是否显示为一个小点
* @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge>
*/
export default {
name: 'UniBadge',
emits: ['click'],
props: {
type: {
type: String,
default: 'default'
default: 'error'
},
inverted: {
type: Boolean,
......@@ -61,7 +68,7 @@
},
size: {
type: String,
default: 'normal'
default: 'small'
},
customStyle: {
type: Object,
......@@ -89,7 +96,7 @@
'uni-badge--' + type,
'uni-badge--' + size,
absolute ? 'uni-badge--absolute' : ''
]
].join(' ')
},
positionStyle() {
if (!this.absolute) return {}
......@@ -123,21 +130,22 @@
const match = whiteList[this.absolute]
return match ? match : whiteList['rightTop']
},
badgeWidth() {
return {
width: `${this.width}px`
}
},
dotStyle() {
if (!this.isDot) return {}
return {
width: '10px',
minWidth: '0',
height: '10px',
padding: '0',
borderRadius: '10px'
}
},
displayValue() {
const { isDot, text, maxNum } = this
const {
isDot,
text,
maxNum
} = this
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
}
},
......@@ -149,10 +157,16 @@
};
</script>
<style lang="scss" scoped>
<style lang="scss" >
$uni-primary: #2979ff !default;
$uni-success: #4cd964 !default;
$uni-warning: #f0ad4e !default;
$uni-error: #dd524d !default;
$uni-info: #909399 !default;
$bage-size: 12px;
$bage-small: scale(0.8);
$bage-height: 20px;
.uni-badge--x {
/* #ifdef APP-NVUE */
......@@ -168,6 +182,11 @@
position: absolute;
}
.uni-badge--small {
transform: $bage-small;
transform-origin: center center;
}
.uni-badge {
/* #ifndef APP-NVUE */
display: flex;
......@@ -176,77 +195,74 @@
/* #endif */
justify-content: center;
flex-direction: row;
height: $bage-height;
line-height: $bage-height;
color: $uni-text-color;
height: 20px;
min-width: 20px;
padding: 0 4px;
line-height: 18px;
color: #fff;
border-radius: 100px;
background-color: $uni-bg-color-hover;
background-color: $uni-info;
background-color: transparent;
border: 1px solid #fff;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-feature-settings: "tnum";
font-size: $bage-size;
/* #ifdef H5 */
z-index: 999;
cursor: pointer;
/* #endif */
}
.uni-badge--inverted {
padding: 0 5px 0 0;
color: $uni-bg-color-hover;
}
&--info {
color: #fff;
background-color: $uni-info;
}
.uni-badge--default {
color: $uni-text-color;
background-color: $uni-bg-color-hover;
}
&--primary {
background-color: $uni-primary;
}
.uni-badge--default-inverted {
color: $uni-text-color-grey;
background-color: transparent;
}
&--success {
background-color: $uni-success;
}
.uni-badge--primary {
color: $uni-text-color-inverse;
background-color: $uni-color-primary;
}
&--warning {
background-color: $uni-warning;
}
.uni-badge--primary-inverted {
color: $uni-color-primary;
background-color: transparent;
}
&--error {
background-color: $uni-error;
}
.uni-badge--success {
color: $uni-text-color-inverse;
background-color: $uni-color-success;
}
&--inverted {
padding: 0 5px 0 0;
color: $uni-info;
}
.uni-badge--success-inverted {
color: $uni-color-success;
background-color: transparent;
}
&--info-inverted {
color: $uni-info;
background-color: transparent;
}
.uni-badge--warning {
color: $uni-text-color-inverse;
background-color: $uni-color-warning;
}
&--primary-inverted {
color: $uni-primary;
background-color: transparent;
}
.uni-badge--warning-inverted {
color: $uni-color-warning;
background-color: transparent;
}
&--success-inverted {
color: $uni-success;
background-color: transparent;
}
.uni-badge--error {
color: $uni-text-color-inverse;
background-color: $uni-color-error;
}
&--warning-inverted {
color: $uni-warning;
background-color: transparent;
}
.uni-badge--error-inverted {
color: $uni-color-error;
background-color: transparent;
}
&--error-inverted {
color: $uni-error;
background-color: transparent;
}
.uni-badge--small {
transform: $bage-small;
transform-origin: center center;
}
</style>
{
"id": "uni-badge",
"displayName": "uni-badge 数字角标",
"version": "1.1.4",
"version": "1.2.1",
"description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
"keywords": [
"",
......@@ -18,11 +18,7 @@
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -39,10 +35,11 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
......@@ -77,6 +74,10 @@
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
......
## Badge 数字角标
> **组件名:uni-badge**
> 代码块: `uBadge`
数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
``template`` 中使用组件
```html
<uni-badge size="small" :text="100" absolute="rightBottom" type="primary">
<button type="default">右上</button>
</uni-badge>
<uni-badge text="1"></uni-badge>
<uni-badge text="2" type="purple" @click="bindClick"></uni-badge>
<uni-badge text="3" type="primary" :inverted="true"></uni-badge>
```
## API
### Badge Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|text |String |- |角标内容 |
|type |String |default|颜色类型,可选值:default(灰色)、primary(蓝色)、success(绿色)、warning(黄色)、error(红色)|
|size |String |normal |Badge 大小,可取值:normal、small |
|is-dot |Boolean|false |不展示数字,只有一个小点 |
|max-num |String/Numbuer|99 |展示封顶的数字值,超过 99 显示99+ |
|custom-style |Object | {} |自定义 Badge 样式, 样式对象语法 |
|inverted |Boolean|false |是否无需背景颜色,为 true 时,背景颜色将变为文字的字体颜色 |
|absolute (不支持 nvue) |String| rightTop|开启绝对定位, 角标将定位到其包裹的标签的四个角上,可选值: rightTop(右上角)、rightBottom(右下角)、leftBottom(左下角) 、leftTop(左上角) |
|offset |Array[number]| [0, 0]|距定位角中心点的偏移量,[-10, -10] 表示向 absolute 指定的方向偏移 10px,[10, 10] 表示向 absolute 指定的反方向偏移 10px,只有存在 absolute 属性时有效,与absolute 的值一一对应(例如:值为rightTop, 对应 offset 为 [right, Top])|
### Badge Events
|事件名 |事件说明 |返回参数 |
|:-: |:-: |:-: |
|@click |点击 Badge 触发事件| - |
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-badge)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge](https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge)
\ No newline at end of file
## 0.1.1(2021-03-04)
- refresh不再读取上一条验证码状态
## 0.6.1(2022-06-23)
- 修复:部分返回值,不符合响应体规范的问题
## 0.6.0(2022-05-27)
- 新增:支持在`uni-config-center`中根据场景值配置
- 修复:弹窗式验证码,输入内容后点击取消,重新打开验证码的值仍然存在的问题
## 0.5.2(2022-05-19)
- 修复在Vue3的兼容问题
## 0.5.1(2022-05-18)
- 修复在某些情况下微信小程序端验证码显示错误的问题
## 0.5.0(2022-05-17)
- 新增支持在`uni-captcha-co`->`config`配置验证码
## 0.4.1(2022-05-16)
- 新增示例项目
## 0.4.0(2022-05-16)
- 集成创建、刷新、显示验证码的云端一体验证码组件
- 云对象`uni-captcha-co`集成获取验证码的api,`getImageCaptcha`
## 0.3.1(2022-05-13)
- 新增 返回值符合响应体规范
## 0.3.0(2022-05-13)
- 新增 支持 uni-config-center 配置
## 0.2.2(2022-04-25)
- 修复 0.2.1 版本引起的使用 image 组件验证码不显示的Bug
## 0.2.1(2022-04-18)
- 更新 优化字体
## 0.2.0(2022-04-14)
- 新增 使用 svg 表现形式更好
- 新增 使用字体,可以任意替换默认字体
- 新增 支持设置字体大小
- 新增 支持忽略某些字符
- 注意 更新之后请重新上传公共模块
## 0.1.0(2021-03-01)
- 调整为uni_modules目录规范
<template>
<view class="captcha-box">
<view class="captcha-img-box">
<uni-icons class="loding" size="20px" color="#BBB" v-if="loging" type="spinner-cycle"></uni-icons>
<image class="captcha-img" :class="{opacity:loging}" @click="getImageCaptcha" :src="captchaBase64"
mode="widthFix"></image>
</view>
<input @blur="focusCaptchaInput = false" :focus="focusCaptchaInput" type="text" class="captcha"
:inputBorder="false" maxlength="4" v-model="val" placeholder="请输入验证码">
</view>
</template>
<script>
export default {
props: {
modelValue:String,
value:String,
scene: {
type: String,
default () {
return ""
}
},
focus: {
type: Boolean,
default () {
return false
}
}
},
computed:{
val:{
get(){
return this.value||this.modelValue
},
set(value){
// console.log(value);
// TODO 兼容 vue2
// #ifdef VUE2
this.$emit('input', value);
// #endif
// TODO 兼容 vue3
// #ifdef VUE3
this.$emit('update:modelValue', value)
// #endif
}
}
},
data() {
return {
focusCaptchaInput: false,
captchaBase64: "",
loging: false
};
},
watch: {
scene: {
handler(scene) {
if (scene) {
this.getImageCaptcha(this.focus)
} else {
uni.showToast({
title: 'scene不能为空',
icon: 'none'
});
}
},
immediate:true
}
},
methods: {
getImageCaptcha(focus = true) {
this.loging = true
if (focus) {
this.val = ''
this.focusCaptchaInput = true
}
const uniIdCo = uniCloud.importObject("uni-captcha-co", {
customUI: true
})
uniIdCo.getImageCaptcha({
scene: this.scene
}).then(result => {
// console.log(result);
this.captchaBase64 = result.captchaBase64
})
.catch(e => {
uni.showToast({
title: e.message,
icon: 'none'
});
}).finally(e => {
this.loging = false
})
}
}
}
</script>
<style lang="scss" scoped>
.captcha-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: flex-end;
flex: 1;
}
.captcha-img-box,
.captcha {
height: 44px;
line-height: 44px;
}
.captcha-img-box {
position: relative;
background-color: #FEFAE7;
}
.captcha {
background-color: #F8F8F8;
font-size: 14px;
flex: 1;
padding: 0 20rpx;
margin-left: 20rpx;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
}
.captcha-img-box,
.captcha-img,
.loding {
height: 44px !important;
width: 100px;
}
.captcha-img{
cursor: pointer;
}
.loding {
z-index: 9;
color: #bbb;
position: absolute;
text-align: center;
line-height: 45px;
animation: rotate 1s linear infinite;
}
.opacity {
opacity: 0.5;
}
@keyframes rotate {
from {
transform: rotate(0deg)
}
to {
transform: rotate(360deg)
}
}
</style>
\ No newline at end of file
<template>
<uni-popup ref="popup" type="center">
<view class="popup-captcha">
<view class="content">
<text class="title">{{title}}</text>
<uni-captcha :focus="focus" :scene="scene" v-model="val"></uni-captcha>
</view>
<view class="button-box">
<view @click="close" class="btn">取消</view>
<view @click="confirm" class="btn confirm">确认</view>
</view>
</view>
</uni-popup>
</template>
<script>
export default {
data() {
return {
focus: false
}
},
props: {
modelValue:String,
value:String,
scene: {
type: String,
default () {
return ""
}
},
title: {
type: String,
default () {
return ""
}
},
},
computed:{
val:{
get(){
return this.value||this.modelValue
},
set(value){
// console.log(value);
// TODO 兼容 vue2
// #ifdef VUE2
this.$emit('input', value);
// #endif
// TODO 兼容 vue3
// #ifdef VUE3
this.$emit('update:modelValue', value)
// #endif
}
}
},
methods: {
open() {
this.focus = true
this.val = ""
this.$refs.popup.open()
},
close() {
this.focus = false
this.$refs.popup.close()
},
confirm() {
if(!this.val||this.val.length < 4){
return uni.showToast({
title: '请填写验证码',
icon: 'none'
});
}
this.close()
this.$emit('confirm')
}
}
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
view {
display: flex;
flex-direction: column;
}
/* #endif */
.popup-captcha {
/* #ifndef APP-NVUE */
display: flex;
max-width: 600px;
/* #endif */
width: 600rpx;
padding-bottom: 0;
background-color: #FFF;
border-radius: 10px;
flex-direction: column;
position: relative;
}
.popup-captcha .content {
padding: 1.3em 0.8em;
}
.popup-captcha .title {
text-align: center;
word-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
font-weight: 400;
font-size: 18px;
overflow: hidden;
text-overflow: ellipsis;
color: #111;
margin-bottom: 15px;
}
.button-box {
height: 44px;
border-top: solid 1px #eee;
flex-direction: row;
align-items: center;
justify-content: space-around;
}
.button-box ,.btn{
height: 44px;
line-height: 44px;
}
.button-box .btn{
flex: 1;
margin: 1px;
text-align: center;
}
.button-box .confirm{
color: #007aff;
border-left: solid 1px #eee;
}
</style>
{
"id": "uni-captcha",
"displayName": "uni-captcha",
"version": "0.1.1",
"description": "简洁、高效、灵活可配置的云端验证码模块",
"version": "0.6.1",
"description": "云端一体图形验证码组件",
"keywords": [
"uniCloud",
"captcha",
"验证码",
"图形验证码",
"人机验证"
"人机验证",
"防刷",
"防脚本"
],
"repository": "https://gitee.com/dcloud/uni-captcha",
"engines": {
......@@ -73,6 +73,10 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
......
## uni 验证码验证文档
> 用途:主要使用在登录、需要人机校验或其他限制调用的场景
> 验证码生成、校验都在服务端。页面使用返回的 base64 显示。[云端一体登陆模板](https://ext.dcloud.net.cn/plugin?id=13)已集成,可下载体验。
> 数据表使用[opendb-verify-codes](https://gitee.com/dcloud/opendb/blob/master/collection/opendb-verify-codes/collection.json)
### 获取验证码@create
用法:`uniCaptcha.create(Object params);`
**参数说明**
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| --------------- | ------ | ---- | ------- | ----------------------------------------------- |
| scene | String | 是 | 4 | 使用场景值,用于防止不同功能的验证码混用 |
| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
| width | Number | - | 100 | 图片宽度 |
| height | Number | - | 40 | 图片高度 |
| backgroundColor | String | - | #FFFAE8 | 验证码背景色 |
| size | Number | - | 4 | 验证码长度,最多 6 个字符 |
| noise | Number | - | 4 | 验证码干扰线条数 |
| expiresDate | Number | - | 180 | 验证码过期时间(s) |
**响应参数**
| 字段 | 类型 | 说明 |
| ------------- | ------ | ------------------- |
| code | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
| captchaBase64 | String | 验证码:base64 格式 |
`注意:`
- 重新生成后,上条验证码作废
### 校验验证码@verify
用法:`uniCaptcha.verify(Object params);`
**参数说明**
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| -------- | ------ | ---- | ------ | ----------------------------------------------- |
| scene | String | 是 | - | 类型,用于防止不同功能的验证码混用 |
| captcha | String | 是 | - | 验证码 |
| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
**响应参数**
| 字段 | 类型 | 说明 |
| ------- | ------ | ------------------ |
| code | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
`注意:`
- 若提示验证码失效,请重新获取
### 刷新验证码@refresh
用法:`uniCaptcha.refresh(Object params);`
**参数说明**
| 字段 | 类型 | 必填 | 默认值 | 说明 |
| -------- | ------ | ---- | ------ | ----------------------------------------------- |
| scene | String | 是 | - | 类型,用于防止不同功能的验证码混用 |
| deviceId | String | - | - | 设备 id,如果不传,将自动从 uniCloud 上下文获取 |
**响应参数**
| 字段 | 类型 | 说明 |
| ------------- | ------ | ------------------- |
| code | Number | 错误码,0 表示成功 |
| message | String | 详细信息 |
| captchaBase64 | String | 验证码:base64 格式 |
`注意:`
- 支持传入 create 方法的所有参数,如果不传,则自动按照 deviceId 匹配上次生成时的配置生成新的验证码
## 错误码
_详细信息请查看 message 中查看_
| 模块 | 模块码 | 错误代码 | 错误信息 |
| :----: | :----: | :------: | :---------------------: |
| 验证码 | 100 | 01 | (10001)验证码生成失败 |
| | | 02 | (10002)验证码校验失败 |
| | | 03 | (10003)验证码刷新失败 |
<h2>
文档已移至 <a href="https://uniapp.dcloud.io/uniCloud/uni-captcha.html" target="_blank">uni-captcha文档</a>
</h2>
\ No newline at end of file
{
"name": "uni-captcha",
"version": "0.1.1",
"version": "0.2.2",
"description": "uni-captcha",
"main": "index.js",
"homepage": "https://ext.dcloud.net.cn/plugin?id=4048",
......@@ -9,5 +9,8 @@
"url": "git+https://gitee.com/dcloud/uni-captcha"
},
"author": "DCloud",
"license": "Apache-2.0"
"license": "Apache-2.0",
"dependencies": {
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
}
}
\ No newline at end of file
// 开发文档: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
//导入验证码公共模块
const uniCaptcha = require('uni-captcha')
//获取数据库对象
const db = uniCloud.database();
//获取数据表opendb-verify-codes对象
const verifyCodes = db.collection('opendb-verify-codes')
module.exports = {
async getImageCaptcha({
scene
}) {
//获取设备id
let {
deviceId,
platform
} = this.getClientInfo();
//根据:设备id、场景值、状态,查找记录是否存在
let res = await verifyCodes.where({
scene,
deviceId,
state: 0
}).limit(1).get()
//如果已存在则调用刷新接口,反之调用插件接口
let action = res.data.length ? 'refresh' : 'create'
//执行并返回结果
//导入配置,配置优先级说明:此处配置 > uni-config-center
return await uniCaptcha[action]({
scene, //来源客户端传递,表示:使用场景值,用于防止不同功能的验证码混用
uniPlatform: platform
})
}
}
{
"name": "uni-captcha-co",
"dependencies": {
"uni-captcha": "file:../common/uni-captcha",
"uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
},
"extensions": {
"uni-cloud-jql": {}
}
}
\ No newline at end of file
{
"bsonType": "object",
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"code": {
"bsonType": "string",
"description": "验证码"
},
"create_date": {
"bsonType": "timestamp",
"description": "创建时间"
},
"device_uuid": {
"bsonType": "string",
"description": "设备UUID,常用于图片验证码"
},
"email": {
"bsonType": "string",
"description": "邮箱"
},
"expired_date": {
"bsonType": "timestamp",
"description": "过期时间"
},
"ip": {
"bsonType": "string",
"description": "请求时客户端IP地址"
},
"mobile": {
"bsonType": "string",
"description": "手机号码"
},
"scene": {
"bsonType": "string",
"description": "使用验证码的场景,如:login, bind, unbind, pay"
},
"state": {
"bsonType": "int",
"description": "验证状态:0 未验证、1 已验证、2 已作废"
}
},
"required": []
}
\ No newline at end of file
## 1.3.1(2021-12-20)
- 修复 在vue页面下略缩图显示不正常的bug
## 1.3.0(2021-11-19)
- 重构插槽的用法 ,header 替换为 title
- 新增 actions 插槽
- 新增 cover 封面图属性和插槽
- 新增 padding 内容默认内边距离
- 新增 margin 卡片默认外边距离
- 新增 spacing 卡片默认内边距
- 新增 shadow 卡片阴影属性
- 取消 mode 属性,可使用组合插槽代替
- 取消 note 属性 ,使用actions插槽代替
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-card](https://uniapp.dcloud.io/component/uniui/uni-card)
## 1.2.1(2021-07-30)
- 优化 vue3下事件警告的问题
## 1.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.8(2021-07-01)
- 优化 图文卡片无图片加载时,提供占位图标
- 新增 header 插槽,自定义卡片头部( 图文卡片 mode="style" 时,不支持)
- 修复 thumbnail 不存在仍然占位的 bug
## 1.1.7(2021-05-12)
- 新增 组件示例地址
## 1.1.6(2021-02-04)
- 调整为uni_modules目录规范
<template>
<view class="uni-card uni-border" :class="{ 'uni-card--full': isFull === true || isFull === 'true', 'uni-card--shadow': isShadow === true || isShadow === 'true'}">
<!-- 基础 -->
<view v-if="mode === 'basic' && title" class="uni-card__header uni-border-bottom" @click.stop="onClick">
<view v-if="thumbnail" class="uni-card__header-extra-img-view">
<image :src="thumbnail" class="uni-card__header-extra-img" />
<view class="uni-card" :class="{ 'uni-card--full': isFull, 'uni-card--shadow': isShadow,'uni-card--border':border}"
:style="{'margin':isFull?0:margin,'padding':spacing,'box-shadow':isShadow?shadow:''}">
<!-- 封面 -->
<slot name="cover">
<view v-if="cover" class="uni-card__cover">
<image class="uni-card__cover-image" mode="widthFix" @click="onClick('cover')" :src="cover"></image>
</view>
<text class="uni-card__header-title-text">{{ title }}</text>
<text v-if="extra" class="uni-card__header-extra-text">{{ extra }}</text>
</view>
<!-- 标题 -->
<view v-if="mode === 'title'" class="uni-card__title uni-border-bottom" @click.stop="onClick">
<view class="uni-card__title-box">
<view class="uni-card__title-header">
<image class="uni-card__title-header-image" :src="thumbnail" mode="scaleToFill" />
</slot>
<slot name="title">
<view v-if="title || extra" class="uni-card__header">
<!-- 卡片标题 -->
<view class="uni-card__header-box" @click="onClick('title')">
<view v-if="thumbnail" class="uni-card__header-avatar">
<image class="uni-card__header-avatar-image" :src="thumbnail" mode="aspectFit" />
</view>
<view class="uni-card__header-content">
<text class="uni-card__header-content-title uni-ellipsis">{{ title }}</text>
<text v-if="title&&subTitle"
class="uni-card__header-content-subtitle uni-ellipsis">{{ subTitle }}</text>
</view>
</view>
<view class="uni-card__title-content">
<text class="uni-card__title-content-title uni-ellipsis">{{ title }}</text>
<text class="uni-card__title-content-extra uni-ellipsis">{{ subTitle }}</text>
<view class="uni-card__header-extra" @click="onClick('extra')">
<text class="uni-card__header-extra-text">{{ extra }}</text>
</view>
</view>
<view v-if="extra">
<text class="uni-card__header-extra-text">{{ extra }}</text>
</view>
</view>
<!-- 图文 -->
<view v-if="mode === 'style'" class="uni-card__thumbnailimage" @click.stop="onClick">
<view class="uni-card__thumbnailimage-box">
<image class="uni-card__thumbnailimage-image" :src="thumbnail" mode="aspectFill" />
</view>
<view v-if="title" class="uni-card__thumbnailimage-title"><text class="uni-card__thumbnailimage-title-text">{{ title }}</text></view>
</view>
<!-- 内容 -->
<view class="uni-card__content uni-card__content--pd" @click.stop="onClick">
<view v-if="mode === 'style' && extra" class=""><text class="uni-card__content-extra">{{ extra }}</text></view>
<slot />
</slot>
<!-- 卡片内容 -->
<view class="uni-card__content" :style="{padding:padding}" @click="onClick('content')">
<slot></slot>
</view>
<!-- 底部 -->
<view v-if="note" class="uni-card__footer uni-border-top">
<slot name="footer">
<text class="uni-card__footer-text">{{ note }}</text>
</slot>
<view class="uni-card__actions" @click="onClick('actions')">
<slot name="actions"></slot>
</view>
</view>
</template>
......@@ -50,21 +41,22 @@
* @description 卡片视图组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=22
* @property {String} title 标题文字
* @property {String} subTitle 副标题(仅仅mode=title下生效)
* @property {String} subTitle 副标题
* @property {Number} padding 内容内边距
* @property {Number} margin 卡片外边距
* @property {Number} spacing 卡片内边距
* @property {String} extra 标题额外信息
* @property {String} note 标题左侧缩略图
* @property {String} thumbnail 底部信息
* @property {String} mode = [basic|style|title] 卡片模式
* @value basic 基础卡片
* @value style 图文卡片
* @value title 标题卡片
* @property {Boolean} isFull = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
* @property {Boolean} isShadow = [true | false] 卡片内容是否开启阴影
* @property {String} cover 封面图(本地路径需要引入)
* @property {String} thumbnail 标题左侧缩略图
* @property {Boolean} is-full = [true | false] 卡片内容是否通栏,为 true 时将去除padding值
* @property {Boolean} is-shadow = [true | false] 卡片内容是否开启阴影
* @property {String} shadow 卡片阴影
* @property {Boolean} border 卡片边框
* @event {Function} click 点击 Card 触发事件
* @example <uni-card title="标题文字" thumbnail="xxx.jpg" extra="额外信息" note="Tips">内容主体,可自定义内容及样式</uni-card>
*/
export default {
name: 'UniCard',
emits: ['click'],
props: {
title: {
type: String,
......@@ -74,11 +66,23 @@
type: String,
default: ''
},
padding: {
type: String,
default: '10px'
},
margin: {
type: String,
default: '15px'
},
spacing: {
type: String,
default: '0 10px'
},
extra: {
type: String,
default: ''
},
note: {
cover: {
type: String,
default: ''
},
......@@ -86,10 +90,6 @@
type: String,
default: ''
},
mode: {
type: String,
default: 'basic'
},
isFull: {
// 内容区域是否通栏
type: Boolean,
......@@ -97,293 +97,157 @@
},
isShadow: {
// 是否开启阴影
type: [Boolean, String],
default: false
type: Boolean,
default: true
},
shadow: {
type: String,
default: '0px 0px 3px 1px rgba(0, 0, 0, 0.08)'
},
border: {
type: Boolean,
default: true
}
},
methods: {
onClick() {
this.$emit('click')
onClick(type) {
this.$emit('click', type)
}
}
}
</script>
<style lang="scss" scoped>
.uni-card {
/* #ifndef APP-NVUE */
display: flex;
flex: 1;
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
/* #endif */
margin: $uni-spacing-col-lg $uni-spacing-row-lg;
background-color: $uni-bg-color;
position: relative;
flex-direction: column;
border-radius: 5px;
overflow: hidden;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
<style lang="scss">
$uni-border-3: #EBEEF5 !default;
$uni-shadow-base:0 0px 6px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-main-color: #3a3a3a !default;
$uni-base-color: #6a6a6a !default;
$uni-secondary-color: #909399 !default;
$uni-spacing-sm: 8px !default;
$uni-border-color:$uni-border-3;
$uni-shadow: $uni-shadow-base;
$uni-card-title: 15px;
$uni-cart-title-color:$uni-main-color;
$uni-card-subtitle: 12px;
$uni-cart-subtitle-color:$uni-secondary-color;
$uni-card-spacing: 10px;
$uni-card-content-color: $uni-base-color;
.uni-border {
position: relative;
/* #ifdef APP-NVUE */
border-color: $uni-border-color;
border-style: solid;
border-width: 0.5px;
/* #endif */
z-index: 1;
}
/* #ifndef APP-NVUE */
.uni-border:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
top: 0;
right: 0;
border: 1px solid $uni-border-color;
border-radius: 10px;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
z-index: -1;
}
/* #endif */
.uni-border-bottom {
position: relative;
/* #ifdef APP-NVUE */
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 0.5px;
/* #endif */
z-index: 1;
}
/* #ifndef APP-NVUE */
.uni-border-bottom:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
top: 0;
right: 0;
border-bottom: 1px solid $uni-border-color;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
z-index: -1;
}
/* #endif */
.uni-border-top {
position: relative;
/* #ifdef APP-NVUE */
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 0.5px;
/* #endif */
z-index: 1;
}
/* #ifndef APP-NVUE */
.uni-border-top:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
top: 0;
right: 0;
border-top: 1px solid $uni-border-color;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
z-index: -1;
}
/* #endif */
.uni-card__thumbnailimage {
position: relative;
flex-direction: column;
justify-content: center;
height: 150px;
overflow: hidden;
}
.uni-card__thumbnailimage-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
overflow: hidden;
}
.uni-card__thumbnailimage-image {
flex: 1;
}
.uni-card__thumbnailimage-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
position: absolute;
bottom: 0;
left: 0;
right: 0;
flex-direction: row;
padding: $uni-spacing-col-base $uni-spacing-col-lg;
background-color: $uni-bg-color-mask;
}
.uni-card__thumbnailimage-title-text {
flex: 1;
font-size: $uni-font-size-base;
color: #fff;
}
.uni-card__title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 10px;
}
.uni-card__title-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
overflow: hidden;
}
.uni-card__title-header {
width: 40px;
height: 40px;
.uni-card {
margin: $uni-card-spacing;
padding: 0 $uni-spacing-sm;
border-radius: 4px;
overflow: hidden;
border-radius: 5px;
}
.uni-card__title-header-image {
width: 40px;
height: 40px;
}
.uni-card__title-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
background-color: #fff;
flex: 1;
padding-left: 10px;
height: 40px;
overflow: hidden;
}
.uni-card__title-content-title {
font-size: $uni-font-size-base;
line-height: 22px;
}
.uni-card__title-content-extra {
font-size: $uni-font-size-sm;
line-height: 27px;
color: $uni-text-color-grey;
}
.uni-card__header {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
position: relative;
flex-direction: row;
padding: $uni-spacing-col-lg;
align-items: center;
}
.uni-card__header-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
margin-right: $uni-spacing-col-base;
justify-content: flex-start;
align-items: center;
}
.uni-card__cover {
position: relative;
margin-top: $uni-card-spacing;
flex-direction: row;
overflow: hidden;
border-radius: 4px;
.uni-card__cover-image {
flex: 1;
// width: 100%;
/* #ifndef APP-PLUS */
vertical-align: middle;
/* #endif */
}
}
.uni-card__header-title-text {
font-size: $uni-font-size-lg;
flex: 1;
color: #333;
}
.uni-card__header {
display: flex;
border-bottom: 1px $uni-border-color solid;
flex-direction: row;
align-items: center;
padding: $uni-card-spacing;
overflow: hidden;
.uni-card__header-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
overflow: hidden;
}
.uni-card__header-extra-img {
height: $uni-img-size-sm;
width: $uni-img-size-sm;
margin-right: $uni-spacing-col-base;
}
.uni-card__header-avatar {
width: 40px;
height: 40px;
overflow: hidden;
border-radius: 5px;
margin-right: $uni-card-spacing;
.uni-card__header-avatar-image {
flex: 1;
width: 40px;
height: 40px;
}
}
.uni-card__header-extra-text {
flex: 1;
margin-left: $uni-spacing-col-base;
font-size: $uni-font-size-sm;
text-align: right;
color: $uni-text-color-grey;
}
.uni-card__header-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
flex: 1;
// height: 40px;
overflow: hidden;
.uni-card__header-content-title {
font-size: $uni-card-title;
color: $uni-cart-title-color;
// line-height: 22px;
}
.uni-card__header-content-subtitle {
font-size: $uni-card-subtitle;
margin-top: 5px;
color: $uni-cart-subtitle-color;
}
}
.uni-card__content {
color: $uni-text-color;
}
.uni-card__header-extra {
line-height: 12px;
.uni-card__content--pd {
padding: $uni-spacing-col-lg;
}
.uni-card__header-extra-text {
font-size: 12px;
color: $uni-cart-subtitle-color;
}
}
}
.uni-card__content-extra {
font-size: $uni-font-size-base;
padding-bottom: 10px;
color: $uni-text-color-grey;
}
.uni-card__content {
padding: $uni-card-spacing;
font-size: 14px;
color: $uni-card-content-color;
line-height: 22px;
}
.uni-card__footer {
justify-content: space-between;
padding: $uni-spacing-col-lg;
.uni-card__actions {
font-size: 12px;
}
}
.uni-card__footer-text {
color: $uni-text-color-grey;
font-size: $uni-font-size-sm;
.uni-card--border {
border: 1px solid $uni-border-color;
}
.uni-card--shadow {
position: relative;
/* #ifndef APP-NVUE */
box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.1);
box-shadow: $uni-shadow;
/* #endif */
}
.uni-card--full {
margin: 0;
border-left-width: 0;
border-left-width: 0;
border-radius: 0;
}
......
{
"id": "uni-card",
"displayName": "Card 卡片",
"version": "1.1.6",
"displayName": "uni-card 卡片",
"version": "1.3.1",
"description": "Card 组件,提供常见的卡片样式。",
"keywords": [
"card",
"uni-ui",
"uniui",
"card",
"",
"卡片"
],
"repository": "https://github.com/dcloudio/uni-ui",
......@@ -39,7 +41,10 @@
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"dependencies": [
"uni-icons",
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
......@@ -74,8 +79,12 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
}
## Card 卡片
> **组件名:uni-card**
> 代码块: `uCard`
卡片视图组件。
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 因为平台兼容问题 , 目前 APP-NVUE 安卓平台下不支持阴影
### 基本用法
``template`` 中使用组件
```html
<!-- 一般用法 -->
<uni-card title="标题文字" thumbnail="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" extra="额外信息" note="Tips">
内容主体,可自定义内容及样式
</uni-card>
<!-- 内容通栏 -->
<uni-card is-full="true" title="DCloud" thumbnail="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" extra="2018.12.12" >
<image src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" style="width: 100%;"></image>
</uni-card>
<!-- 图文卡片模式 -->
<uni-card
title="标题文字"
mode="style"
:is-shadow="true"
thumbnail="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
extra="Dcloud 2019-05-20 12:32:19"
note="Tips"
>
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可编译到iOS、Android、H5、以及各种小程序等多个平台。即使不跨端,uni-app同时也是更好的小程序开发框架。
</uni-card>
<!-- 标题卡片模式 -->
<uni-card
title="Dcloud"
mode="title"
:is-shadow="true"
thumbnail="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
extra="技术没有上限"
note="Tips"
>
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可编译到iOS、Android、H5、以及各种小程序等多个平台。即使不跨端,uni-app同时也是更好的小程序开发框架。
</uni-card>
<!-- 自定义底部按钮 -->
<uni-card title="Dcloud" note="true">
默认内容
<template v-slot:footer>
<view class="footer-box">
<view>喜欢</view>
<view>评论</view>
<view>分享</view>
</view>
</template>
</uni-card>
```
## API
### Card Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|title |String |- |标题文字 |
|extra |String |- |标题额外信息 |
|note |String |- |底部信息 |
|thumbnail |String |- |标题左侧缩略图,支持网络图片,本地图片,本图片需要传入一个绝对路径,如:`/static/xxx.png` |
|mode |String |basic |卡片模式 ,可选值, basic:基础卡片 ;style :图文卡片 ; title :标题卡片 |
|isFull |Boolean|false |卡片内容是否通栏,为true时将去除padding值 |
|isShadow |Boolean|false |卡片内容是否开启阴影 |
### Card Events
|事件称名 |事件说明 |返回参数 |
|:-: |:-: |:-: |
|@click |点击 Card 触发事件 |- |
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-card)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
### Card Slots
|插槽称名 |说明 |
|:-: |:-: |
|footer |卡片底部插槽 |
\ No newline at end of file
## 0.0.2(2021-04-16)
- 修改插件package信息
## 0.0.1(2021-03-15)
- 初始化项目
{
"id": "uni-config-center",
"displayName": "uni-config-center",
"version": "0.0.1",
"version": "0.0.2",
"description": "uniCloud 配置中心",
"keywords": [
"配置",
......@@ -18,10 +18,10 @@
],
"sale": {
"regular": {
"price": 0
"price": "0.00"
},
"sourcecode": {
"price": 0
"price": "0.00"
}
},
"contact": {
......
......@@ -36,7 +36,7 @@ cloudfunctions
使用uni-config-center后的优势
- 配置文件统一管理,对插件作者来说发布插件更简单了,对用户来说使用也更简单了
- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持)
# 用法
......
{
"name": "uni-config-center",
"version": "0.0.1",
"version": "0.0.2",
"description": "配置中心",
"main": "index.js",
"keywords": [],
"author": "fxy060608",
"author": "DCloud",
"license": "Apache-2.0"
}
\ No newline at end of file
## 1.0.2(2022-06-30)
- 优化 在 uni-forms 中的依赖注入方式
## 1.0.1(2022-02-07)
- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
## 1.0.0(2021-11-19)
......
......@@ -155,17 +155,17 @@
value(newVal) {
this.dataList = this.getDataList(newVal)
// fix by mehaotian is_reset 在 uni-forms 中定义
if(!this.is_reset){
this.is_reset = false
this.formItem && this.formItem.setValue(newVal)
}
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
},
modelValue(newVal) {
this.dataList = this.getDataList(newVal);
if(!this.is_reset){
this.is_reset = false
this.formItem && this.formItem.setValue(newVal)
}
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
}
},
data() {
......@@ -193,22 +193,22 @@
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
// this.form = this.getForm('uniForms')
// this.formItem = this.getForm('uniFormsItem')
// this.formItem && this.formItem.setValue(this.value)
if (this.formItem) {
this.isTop = 6
if (this.formItem.name) {
// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
if(!this.is_reset){
this.is_reset = false
this.formItem.setValue(this.dataValue)
}
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
// if (this.formItem) {
// this.isTop = 6
// if (this.formItem.name) {
// // 如果存在name添加默认值,否则formData 中不存在这个字段不校验
// if(!this.is_reset){
// this.is_reset = false
// this.formItem.setValue(this.dataValue)
// }
// this.rename = this.formItem.name
// this.form.inputChildrens.push(this)
// }
// }
if (this.localdata && this.localdata.length !== 0) {
this.isLocal = true
......@@ -273,7 +273,7 @@
}
}
}
this.formItem && this.formItem.setValue(detail.value)
// this.formItem && this.formItem.setValue(detail.value)
// TODO 兼容 vue2
this.$emit('input', detail.value);
// // TOTO 兼容 vue3
......@@ -375,7 +375,7 @@
selectedArr.push(item[this.map.value])
}
})
return this.dataValue && this.dataValue.length > 0 ? this.dataValue : selectedArr
return this.dataValue.length > 0 ? this.dataValue : selectedArr
},
/**
......
{
"id": "uni-data-checkbox",
"displayName": "uni-data-checkbox 数据选择器",
"version": "1.0.1",
"version": "1.0.2",
"description": "通过数据驱动的单选框和复选框",
"keywords": [
"uni-ui",
......
## 1.0.7(2022-07-06)
- 优化 pc端图标位置不正确的问题
## 1.0.6(2022-07-05)
- 优化 显示样式
## 1.0.5(2022-07-04)
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.0.4(2022-04-19)
- 修复 字节小程序 本地数据无法选择下一级的Bug
## 1.0.3(2022-02-25)
......
......@@ -10,7 +10,7 @@
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
<view class="selected-list">
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
<text>{{item.text}}</text><text v-if="index<inputSelected.length-1"
<text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
class="input-split-line">{{split}}</text>
</view>
</view>
......@@ -18,7 +18,7 @@
<text v-else class="selected-area placeholder">{{placeholder}}</text>
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear"
@click.stop="clear">
<uni-icons type="clear" color="#e1e1e1" size="14"></uni-icons>
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
</view>
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
<view class="input-arrow"></view>
......@@ -212,7 +212,9 @@
},
onchange(e) {
this.hide()
this.inputSelected = e
this.$nextTick(() => {
this.inputSelected = e;
})
this._dispatchEvent(e)
},
_processReadonly(dataList, value) {
......@@ -294,6 +296,7 @@
<style >
.uni-data-tree {
flex: 1;
position: relative;
font-size: 14px;
}
......@@ -310,12 +313,14 @@
align-items: center;
flex-wrap: nowrap;
font-size: 14px;
line-height: 38px;
padding: 0 5px;
/* line-height: 35px; */
padding: 0 10px;
padding-right: 5px;
overflow: hidden;
height: 35px;
/* #ifdef APP-NVUE */
height: 40px;
/* #endif */
box-sizing: border-box;
}
.input-value-border {
......@@ -347,19 +352,24 @@
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
/* padding: 0 5px; */
}
.selected-item {
flex-direction: row;
padding: 0 1px;
/* padding: 0 1px; */
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.text-color {
color: #333;
}
.placeholder {
color: grey;
font-size: 12px;
}
.input-split-line {
......@@ -475,6 +485,11 @@
flex: 1;
overflow: hidden;
}
.icon-clear {
display: flex;
align-items: center;
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
......@@ -500,7 +515,7 @@
}
.icon-clear {
margin-right: 5px;
/* margin-right: 5px; */
}
}
......
......@@ -5,16 +5,16 @@
<template v-for="(item,index) in selected">
<view class="selected-item"
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
:key="index" v-if="item.text" @click="handleSelect(index)">
v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList">
<template v-for="(child, i) in dataList" >
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" :key="j"
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child"
@click="handleNodeClick(item, i, j)">
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
......
{
"id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "1.0.4",
"version": "1.0.7",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
......@@ -76,7 +76,8 @@
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
"QQ": "y",
"京东": "u"
},
"快应用": {
"华为": "u",
......
## 2.2.8(2022-09-08)
- 修复 close事件无效的 bug
## 2.2.7(2022-09-05)
- 修复 移动端 maskClick 无效的 bug,详见:[https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false](https://ask.dcloud.net.cn/question/140824?item_id=209458&rf=false)
## 2.2.6(2022-06-30)
- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
## 2.2.5(2022-06-24)
- 修复 日历顶部年月及底部确认未国际化 bug
## 2.2.4(2022-03-31)
......
<template>
<view class="uni-calendar" @mouseleave="leaveCale">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
@click="clean"></view>
@click="clean();maskClick()"></view>
<view v-if="insert || show" class="uni-calendar__content"
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
......@@ -411,6 +411,11 @@
this.close()
},
// 蒙版点击事件
maskClick() {
this.$emit('maskClose')
},
clearCalender() {
if (this.range) {
this.timeRange.startTime = ''
......
......@@ -5,12 +5,12 @@
<view class="uni-date-editor--x" :class="{'uni-date-editor--x__disabled': disabled,
'uni-date-x--border': border}">
<view v-if="!isRange" class="uni-date-x uni-date-single">
<uni-icons type="calendar" color="#e1e1e1" size="22"></uni-icons>
<uni-icons type="calendar" color="#c0c4cc" size="22"></uni-icons>
<input class="uni-date__x-input" type="text" v-model="singleVal"
:placeholder="singlePlaceholderText" :disabled="true" />
</view>
<view v-else class="uni-date-x uni-date-range">
<uni-icons type="calendar" color="#e1e1e1" size="22"></uni-icons>
<uni-icons type="calendar" color="#c0c4cc" size="22"></uni-icons>
<input class="uni-date__x-input t-c" type="text" v-model="range.startDate"
:placeholder="startPlaceholderText" :disabled="true" />
<slot>
......@@ -20,7 +20,7 @@
:placeholder="endPlaceholderText" :disabled="true" />
</view>
<view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
<uni-icons type="clear" color="#e1e1e1" size="18"></uni-icons>
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
</view>
</view>
</slot>
......@@ -91,7 +91,7 @@
<calendar v-show="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime"
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false"
:hideSecond="hideSecond" @confirm="mobileChange" />
:hideSecond="hideSecond" @confirm="mobileChange" @maskClose="close" />
</view>
</template>
<script>
......@@ -127,10 +127,23 @@
export default {
name: 'UniDatetimePicker',
options: {
virtualHost: true
},
components: {
calendar,
timePicker
},
inject: {
form: {
from: 'uniForm',
default: null
},
formItem: {
from: 'uniFormItem',
default: null
},
},
data() {
return {
isRange: false,
......@@ -386,33 +399,16 @@
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
// if (this.formItem) {
// if (this.formItem.name) {
// this.rename = this.formItem.name
// this.form.inputChildrens.push(this)
// }
// if (this.form && this.formItem) {
// this.$watch('formItem.errMsg', (newVal) => {
// this.localMsg = newVal
// })
// }
},
mounted() {
this.platform()
},
methods: {
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
initPicker(newVal) {
if (!newVal || Array.isArray(newVal) && !newVal.length) {
this.$nextTick(() => {
......@@ -520,6 +516,7 @@
setTimeout(() => {
this.popup = false
this.$emit('maskClick', this.value)
this.$refs.mobile.close()
}, 20)
},
setEmit(value) {
......@@ -545,7 +542,8 @@
}
}
}
this.formItem && this.formItem.setValue(value)
this.$emit('change', value)
this.$emit('input', value)
this.$emit('update:modelValue', value)
......@@ -710,7 +708,15 @@
this.$refs.pcSingle && this.$refs.pcSingle.clearCalender()
}
if (needEmit) {
this.formItem && this.formItem.setValue('')
// 校验规则
// if(this.form && this.formItem){
// const {
// validateTrigger
// } = this.form
// if (validateTrigger === 'blur') {
// this.formItem.onFieldChange()
// }
// }
this.$emit('change', '')
this.$emit('input', '')
this.$emit('update:modelValue', '')
......@@ -730,7 +736,6 @@
this.$refs.right && this.$refs.right.next()
}
if (needEmit) {
this.formItem && this.formItem.setValue([])
this.$emit('change', [])
this.$emit('input', [])
this.$emit('update:modelValue', [])
......@@ -779,6 +784,12 @@
</script>
<style>
.uni-date {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
flex: 1;
}
.uni-date-x {
display: flex;
flex-direction: row;
......@@ -789,25 +800,25 @@
background-color: #fff;
color: #666;
font-size: 14px;
flex: 1;
}
.uni-date-x--border {
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #dcdfe6;
border: 1px solid #e5e5e5;
}
.uni-date-editor--x {
display: flex;
align-items: center;
position: relative;
}
.uni-date-editor--x .uni-date__icon-clear {
position: absolute;
top: 0;
right: 0;
display: inline-block;
box-sizing: border-box;
border: 9px solid transparent;
padding: 0 5px;
display: flex;
align-items: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
......@@ -815,10 +826,15 @@
.uni-date__x-input {
padding: 0 8px;
height: 40px;
width: 100%;
line-height: 40px;
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
position: relative;
overflow: hidden;
flex: 1;
line-height: 1;
font-size: 14px;
height: 35px;
}
.t-c {
......
{
"id": "uni-datetime-picker",
"displayName": "uni-datetime-picker 日期选择器",
"version": "2.2.5",
"version": "2.2.8",
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
"keywords": [
"uni-datetime-picker",
......@@ -17,11 +17,7 @@
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -38,7 +34,8 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
......
## 1.1.0(2022-06-30)
- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
- 新增 clear 事件,点击右侧叉号图标触发
- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
-
## 1.0.5(2022-06-07)
- 优化 clearable 显示策略
## 1.0.4(2022-06-07)
......
<template>
<view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="{color:inputBorder && msg?'#e43d33':styles.color}">
<view class="uni-easyinput__content" :class="{'is-input-border':inputBorder ,'is-input-error-border':inputBorder && msg,'is-textarea':type==='textarea','is-disabled':disabled}"
:style="{'border-color':inputBorder && msg?'#dd524d':styles.borderColor,'background-color':disabled?styles.disableColor:''}">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')"></uni-icons>
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{'input-padding':inputBorder}"
:name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" placeholder-class="uni-easyinput__placeholder-class"
:maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" @input="onInput" @blur="onBlur" @focus="onFocus"
@confirm="onConfirm"></textarea>
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input" :style="{
'padding-right':type === 'password' ||clearable || prefixIcon?'':'10px',
'padding-left':prefixIcon?'':'10px'
}"
:name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" :confirmType="confirmType" @focus="onFocus"
@blur="onBlur" @input="onInput" @confirm="onConfirm" />
<template v-if="type === 'password' && passwordIcon" >
<uni-icons v-if="val" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}" :type="showPassword?'eye-slash-filled':'eye-filled'"
:size="18" color="#c0c4cc" @click="onEyes"></uni-icons>
<view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="boxStyle">
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc"
@click="onClickIcon('prefix')" size="22"></uni-icons>
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea"
:class="{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" :disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused"
:autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm"></textarea>
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input"
:style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'"
:placeholder="placeholder" :placeholderStyle="placeholderStyle"
placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength"
:focus="focused" :confirmType="confirmType" @focus="_Focus" @blur="_Blur" @input="onInput"
@confirm="onConfirm" />
<template v-if="type === 'password' && passwordIcon">
<!-- 开启密码时显示小眼睛 -->
<uni-icons v-if="isVal" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}"
:type="showPassword?'eye-slash-filled':'eye-filled'" :size="22"
:color="focusShow?'#2979ff':'#c0c4cc'" @click="onEyes">
</uni-icons>
</template>
<template v-else-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')"></uni-icons>
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc"
@click="onClickIcon('suffix')" size="22"></uni-icons>
</template>
<template v-else>
<uni-icons class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
v-if="clearable && val && !disabled" color="#c0c4cc" @click="onClear"></uni-icons>
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon"
:class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
:color="msg?'#dd524d':(focusShow?'#2979ff':'#c0c4cc')" @click="onClear"></uni-icons>
</template>
<slot name="right"></slot>
</view>
......@@ -31,10 +36,6 @@
</template>
<script>
// import {
// debounce,
// throttle
// } from './common.js'
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
......@@ -48,7 +49,7 @@
* @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
* @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件,点击可清空输入框内容(默认true)
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认false)
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true)
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点(默认false)
......@@ -76,13 +77,44 @@
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
function obj2strClass(obj) {
let classess = ''
for (let key in obj) {
const val = obj[key]
if (val) {
classess += `${key} `
}
}
return classess
}
export default {
function obj2strStyle(obj) {
let style = ''
for (let key in obj) {
const val = obj[key]
style += `${key}:${val};`
}
return style
}
export default {
name: 'uni-easyinput',
emits:['click','iconClick','update:modelValue','input','focus','blur','confirm'],
model:{
prop:'modelValue',
event:'update:modelValue'
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change'],
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
options: {
virtualHost: true
},
inject: {
form: {
from: 'uniForm',
default: null
},
formItem: {
from: 'uniFormItem',
default: null
},
},
props: {
name: String,
......@@ -100,7 +132,10 @@
type: Boolean,
default: false
},
placeholder: String,
placeholder: {
type: String,
default: ' '
},
placeholderStyle: String,
focus: {
type: Boolean,
......@@ -120,7 +155,7 @@
},
clearSize: {
type: [Number, String],
default: 15
default: 24
},
inputBorder: {
type: Boolean,
......@@ -138,7 +173,7 @@
type: [Boolean, String],
default: true
},
passwordIcon:{
passwordIcon: {
type: Boolean,
default: true
},
......@@ -152,79 +187,105 @@
}
}
},
errorMessage:{
type:[String,Boolean],
default:''
errorMessage: {
type: [String, Boolean],
default: ''
}
},
data() {
return {
focused: false,
errMsg: '',
val: '',
showMsg: '',
border: false,
isFirstBorder: false,
showClearIcon: false,
showPassword: false
showPassword: false,
focusShow: false,
localMsg: ''
};
},
computed: {
// 输入框内是否有值
isVal() {
const val = this.val
// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
if (val || val === 0) {
return true
}
return false
},
msg() {
return this.errorMessage || this.errMsg;
// console.log('computed', this.form, this.formItem);
// if (this.form) {
// return this.errorMessage || this.formItem.errMsg;
// }
// TODO 处理头条 formItem 中 errMsg 不更新的问题
return this.localMsg || this.errorMessage
},
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
inputMaxlength() {
return Number(this.maxlength);
},
// 处理外层样式的style
boxStyle() {
return `color:${this.inputBorder && this.msg?'#e43d33':this.styles.color};`
},
// input 内容的类和样式处理
inputContentClass() {
return obj2strClass({
'is-input-border': this.inputBorder,
'is-input-error-border': this.inputBorder && this.msg,
'is-textarea': this.type === 'textarea',
'is-disabled': this.disabled
})
},
inputContentStyle() {
const focusColor = this.focusShow ? '#2979ff' : this.styles.borderColor
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor
return obj2strStyle({
'border-color': borderColor || '#e5e5e5',
'background-color': this.disabled ? this.styles.disableColor : '#fff'
})
},
// input右侧样式
inputStyle() {
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px'
return obj2strStyle({
'padding-right': paddingRight,
'padding-left': this.prefixIcon ? '' : '10px'
})
}
},
watch: {
value(newVal) {
if (this.errMsg) this.errMsg = ''
this.val = newVal
// fix by mehaotian is_reset 在 uni-forms 中定义
if (this.form && this.formItem &&!this.is_reset) {
this.is_reset = false
this.formItem.setValue(newVal)
}
},
modelValue(newVal) {
if (this.errMsg) this.errMsg = ''
this.val = newVal
if (this.form && this.formItem &&!this.is_reset) {
this.is_reset = false
this.formItem.setValue(newVal)
}
},
focus(newVal) {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
})
}
},
created() {
if(!this.value && this.value !== 0){
this.val = this.modelValue
}
if(!this.modelValue && this.modelValue !== 0){
this.val = this.value
}
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
this.init()
// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
if (this.form && this.formItem) {
if (this.formItem.name) {
if(!this.is_reset){
this.is_reset = false
this.formItem.setValue(this.val)
}
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
this.$watch('formItem.errMsg', (newVal) => {
this.localMsg = newVal
})
}
},
mounted() {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
})
},
methods: {
......@@ -232,28 +293,35 @@
* 初始化变量值
*/
init() {
if (this.value || this.value === 0) {
this.val = this.value
} else if (this.modelValue || this.modelValue === 0) {
this.val = this.modelValue
} else {
this.val = null
}
},
/**
* 点击图标时触发
* @param {Object} type
*/
onClickIcon(type) {
this.$emit('iconClick', type)
},
/**
* 获取父元素实例
* 显示隐藏内容,密码框时生效
*/
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
},
onEyes() {
this.showPassword = !this.showPassword
this.$emit('eyes', this.showPassword)
},
/**
* 输入时触发
* @param {Object} event
*/
onInput(event) {
let value = event.detail.value;
// 判断是否去除空格
......@@ -270,30 +338,79 @@
// TODO 兼容 vue2
this.$emit('input', value);
// TODO 兼容 vue3
this.$emit('update:modelValue',value)
this.$emit('update:modelValue', value)
},
onFocus(event) {
/**
* 外部调用方法
* 获取焦点时触发
* @param {Object} event
*/
onFocus() {
this.$nextTick(() => {
this.focused = true
})
this.$emit('focus', null);
},
_Focus(event) {
this.focusShow = true
this.$emit('focus', event);
},
onBlur(event) {
/**
* 外部调用方法
* 失去焦点时触发
* @param {Object} event
*/
onBlur() {
this.focused = false
this.$emit('focus', null);
},
_Blur(event) {
let value = event.detail.value;
this.focusShow = false
this.$emit('blur', event);
// 根据类型返回值,在event中获取的值理论上讲都是string
this.$emit('change', this.val)
// 失去焦点时参与表单校验
if (this.form && this.formItem) {
const {
validateTrigger
} = this.form
if (validateTrigger === 'blur') {
this.formItem.onFieldChange()
}
}
},
/**
* 按下键盘的发送键
* @param {Object} e
*/
onConfirm(e) {
this.$emit('confirm', e.detail.value);
this.$emit('confirm', this.val);
this.$emit('change', this.val)
},
/**
* 清理内容
* @param {Object} event
*/
onClear(event) {
this.val = '';
// TODO 兼容 vue2
this.$emit('input', '');
// TODO 兼容 vue2
// TODO 兼容 vue3
this.$emit('update:modelValue','')
},
fieldClick() {
this.$emit('click');
this.$emit('update:modelValue', '')
// 点击叉号触发
this.$emit('clear')
},
/**
* 去除空格
*/
trimStr(str, pos = 'both') {
if (pos === 'both') {
return str.trim();
......@@ -316,9 +433,10 @@
};
</script>
<style lang="scss" >
<style lang="scss">
$uni-error: #e43d33;
$uni-border-1: #DCDFE6 !default;
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
......@@ -336,10 +454,14 @@
width: 100%;
display: flex;
box-sizing: border-box;
min-height: 36px;
// min-height: 36px;
/* #endif */
flex-direction: row;
align-items: center;
// 处理border动画刚开始显示黑色的问题
border-color: #fff;
transition-property: border-color;
transition-duration: 0.3s;
}
.uni-easyinput__content-input {
......@@ -351,12 +473,16 @@
flex: 1;
line-height: 1;
font-size: 14px;
height: 35px;
// min-height: 36px;
}
.uni-easyinput__placeholder-class {
color: #999;
font-size: 12px;
font-weight: 200;
// font-weight: 200;
}
.is-textarea {
align-items: flex-start;
}
......@@ -371,9 +497,10 @@
flex: 1;
line-height: 1.5;
font-size: 14px;
padding-top: 6px;
padding-bottom: 10px;
margin: 6px;
margin-left: 0;
height: 80px;
min-height: 80px;
/* #ifndef APP-NVUE */
min-height: 80px;
width: auto;
......@@ -403,6 +530,9 @@
align-items: center;
border: 1px solid $uni-border-1;
border-radius: 4px;
/* #ifdef MP-ALIPAY */
overflow: hidden;
/* #endif */
}
.uni-error-message {
......@@ -423,8 +553,10 @@
.is-input-error-border {
border-color: $uni-error;
.uni-easyinput__placeholder-class {
color: mix(#fff, $uni-error, 50%);;
color: mix(#fff, $uni-error, 50%);
;
}
}
......@@ -450,9 +582,9 @@
}
.is-disabled {
border-color: red;
background-color: #F7F6F6;
color: #D5D5D5;
.uni-easyinput__placeholder-class {
color: #D5D5D5;
font-size: 12px;
......
{
"id": "uni-easyinput",
"displayName": "uni-easyinput 增强输入框",
"version": "1.0.5",
"version": "1.1.0",
"description": "Easyinput 组件是对原生input组件的增强",
"keywords": [
"uni-ui",
......
## 1.2.4(2022-09-07)
小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false)
## 1.2.3(2022-09-05)
- 修复 nvue 环境下,具有 tabBar 时,fab 组件下部位置无法正常获取 --window-bottom 的bug,详见:[https://ask.dcloud.net.cn/question/110638?notification_id=826310](https://ask.dcloud.net.cn/question/110638?notification_id=826310)
## 1.2.2(2021-12-29)
- 更新 组件依赖
## 1.2.1(2021-11-19)
- 修复 阴影颜色不正确的bug
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-fab](https://uniapp.dcloud.io/component/uniui/uni-fab)
## 1.1.1(2021-11-09)
- 新增 提供组件设计资源,组件样式调整
## 1.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.7(2021-05-12)
- 新增 组件示例地址
## 1.0.6(2021-02-05)
......
......@@ -5,8 +5,9 @@
'uni-fab--rightBottom': rightBottom,
'uni-fab--leftTop': leftTop,
'uni-fab--rightTop': rightTop
}"
class="uni-fab">
}" class="uni-fab"
:style="nvueBottom"
>
<view :class="{
'uni-fab__content--left': horizontal === 'left',
'uni-fab__content--right': horizontal === 'right',
......@@ -14,14 +15,15 @@
'uni-fab__content--flexDirectionStart': flexDirectionStart,
'uni-fab__content--flexDirectionEnd': flexDirectionEnd,
'uni-fab__content--other-platform': !isAndroidNvue
}"
:style="{ width: boxWidth, height: boxHeight, backgroundColor: styles.backgroundColor }" class="uni-fab__content"
elevation="5">
}" :style="{ width: boxWidth, height: boxHeight, backgroundColor: styles.backgroundColor }"
class="uni-fab__content" elevation="5">
<view v-if="flexDirectionStart || horizontalLeft" class="uni-fab__item uni-fab__item--first" />
<view v-for="(item, index) in content" :key="index" :class="{ 'uni-fab__item--active': isShow }" class="uni-fab__item"
@click="_onItemClick(index, item)">
<image :src="item.active ? item.selectedIconPath : item.iconPath" class="uni-fab__item-image" mode="widthFix" />
<text class="uni-fab__item-text" :style="{ color: item.active ? styles.selectedColor : styles.color }">{{ item.text }}</text>
<view v-for="(item, index) in content" :key="index" :class="{ 'uni-fab__item--active': isShow }"
class="uni-fab__item" @click="_onItemClick(index, item)">
<image :src="item.active ? item.selectedIconPath : item.iconPath" class="uni-fab__item-image"
mode="aspectFit" />
<text class="uni-fab__item-text"
:style="{ color: item.active ? styles.selectedColor : styles.color }">{{ item.text }}</text>
</view>
<view v-if="flexDirectionEnd || horizontalRight" class="uni-fab__item uni-fab__item--first" />
</view>
......@@ -32,10 +34,11 @@
'uni-fab__circle--leftTop': leftTop,
'uni-fab__circle--rightTop': rightTop,
'uni-fab__content--other-platform': !isAndroidNvue
}"
class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor }" @click="_onClick">
<view class="fab-circle-v" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
<view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
}" class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor, 'bottom': nvueBottom }" @click="_onClick">
<uni-icons class="fab-circle-icon" type="plusempty" :color="styles.iconColor" size="32"
:class="{'uni-fab__plus--active': isShow && content.length > 0}"></uni-icons>
<!-- <view class="fab-circle-v" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
<view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view> -->
</view>
</view>
</template>
......@@ -67,6 +70,7 @@
*/
export default {
name: 'UniFab',
emits: ['fabClick', 'trigger'],
props: {
pattern: {
type: Object,
......@@ -110,16 +114,17 @@
color: '#3c3e49',
selectedColor: '#007AFF',
backgroundColor: '#fff',
buttonColor: '#007AFF'
buttonColor: '#007AFF',
iconColor: '#fff'
}
}
},
computed: {
contentWidth(e) {
return (this.content.length + 1) * 55 + 10 + 'px'
return (this.content.length + 1) * 55 + 15 + 'px'
},
contentWidthMin() {
return 55 + 'px'
return '55px'
},
// 动态计算宽度
boxWidth() {
......@@ -155,12 +160,24 @@
},
horizontalRight() {
return this.getPosition(2, 'horizontal', 'right')
},
// 计算 nvue bottom
nvueBottom() {
const safeBottom = uni.getSystemInfoSync().windowBottom;
// #ifdef APP-NVUE
return 30 + safeBottom
// #endif
// #ifndef APP-NVUE
return 30
// #endif
}
},
watch: {
pattern(newValue, oldValue) {
//console.log(JSON.stringify(newValue))
this.styles = Object.assign({}, this.styles, newValue)
pattern: {
handler(val, oldVal) {
this.styles = Object.assign({}, this.styles, val)
},
deep: true
}
},
created() {
......@@ -212,7 +229,9 @@
}
</script>
<style lang="scss" scoped>
<style lang="scss" >
$uni-shadow-base:0 1px 5px 2px rgba($color: #000000, $alpha: 0.3) !default;
.uni-fab {
position: fixed;
/* #ifndef APP-NVUE */
......@@ -221,8 +240,10 @@
justify-content: center;
align-items: center;
z-index: 10;
border-radius: 45px;
box-shadow: $uni-shadow-base;
}
.uni-cursor-point {
/* #ifdef H5 */
cursor: pointer;
......@@ -234,43 +255,43 @@
}
.uni-fab--leftBottom {
left: 5px;
bottom: 20px;
left: 15px;
bottom: 30px;
/* #ifdef H5 */
left: calc(5px + var(--window-left));
bottom: calc(20px + var(--window-bottom));
left: calc(15px + var(--window-left));
bottom: calc(30px + var(--window-bottom));
/* #endif */
padding: 10px;
// padding: 10px;
}
.uni-fab--leftTop {
left: 5px;
left: 15px;
top: 30px;
/* #ifdef H5 */
left: calc(5px + var(--window-left));
left: calc(15px + var(--window-left));
top: calc(30px + var(--window-top));
/* #endif */
padding: 10px;
// padding: 10px;
}
.uni-fab--rightBottom {
right: 5px;
bottom: 20px;
right: 15px;
bottom: 30px;
/* #ifdef H5 */
right: calc(5px + var(--window-right));
bottom: calc(20px + var(--window-bottom));
right: calc(15px + var(--window-right));
bottom: calc(30px + var(--window-bottom));
/* #endif */
padding: 10px;
// padding: 10px;
}
.uni-fab--rightTop {
right: 5px;
right: 15px;
top: 30px;
/* #ifdef H5 */
right: calc(5px + var(--window-right));
right: calc(15px + var(--window-right));
top: calc(30px + var(--window-top));
/* #endif */
padding: 10px;
// padding: 10px;
}
.uni-fab__circle {
......@@ -283,8 +304,9 @@
width: 55px;
height: 55px;
background-color: #3c3e49;
border-radius: 55px;
border-radius: 45px;
z-index: 11;
// box-shadow: $uni-shadow-base;
}
.uni-fab__circle--leftBottom {
......@@ -298,10 +320,10 @@
.uni-fab__circle--leftTop {
left: 15px;
top: 40px;
top: 30px;
/* #ifdef H5 */
left: calc(15px + var(--window-left));
top: calc(40px + var(--window-top));
top: calc(30px + var(--window-top));
/* #endif */
}
......@@ -316,10 +338,10 @@
.uni-fab__circle--rightTop {
right: 15px;
top: 40px;
top: 30px;
/* #ifdef H5 */
right: calc(15px + var(--window-right));
top: calc(40px + var(--window-top));
top: calc(30px + var(--window-top));
/* #endif */
}
......@@ -343,26 +365,42 @@
font-weight: bold;
}
.fab-circle-v {
position: absolute;
width: 3px;
height: 31px;
left: 26px;
top: 12px;
background-color: white;
transform: rotate(0deg);
transition: transform 0.3s;
}
.fab-circle-h {
position: absolute;
width: 31px;
height: 3px;
left: 12px;
top: 26px;
background-color: white;
// .fab-circle-v {
// position: absolute;
// width: 2px;
// height: 24px;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// /* #ifndef APP-NVUE */
// margin: auto;
// /* #endif */
// background-color: white;
// transform: rotate(0deg);
// transition: transform 0.3s;
// }
// .fab-circle-h {
// position: absolute;
// width: 24px;
// height: 2px;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// /* #ifndef APP-NVUE */
// margin: auto;
// /* #endif */
// background-color: white;
// transform: rotate(0deg);
// transition: transform 0.3s;
// }
.fab-circle-icon {
transform: rotate(0deg);
transition: transform 0.3s;
font-weight: 200;
}
.uni-fab__plus--active {
......@@ -387,7 +425,7 @@
.uni-fab__content--other-platform {
border-width: 0px;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
box-shadow: $uni-shadow-base;
}
.uni-fab__content--left {
......@@ -431,14 +469,16 @@
}
.uni-fab__item-image {
width: 25px;
height: 25px;
margin-bottom: 3px;
width: 20px;
height: 20px;
margin-bottom: 4px;
}
.uni-fab__item-text {
color: #FFFFFF;
font-size: 12px;
line-height: 12px;
margin-top: 2px;
}
.uni-fab__item--first {
......
{
"id": "uni-fab",
"displayName": "uni-fab 悬浮按钮",
"version": "1.0.7",
"version": "1.2.4",
"description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
"keywords": [
"uni-ui",
......@@ -17,11 +17,7 @@
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
......@@ -38,10 +34,11 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"dependencies": ["uni-scss","uni-icons"],
"encrypt": [],
"platforms": {
"cloud": {
......@@ -76,6 +73,10 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
......
## Fab 悬浮按钮
> **组件名:uni-fab**
> 代码块: `uFab`
......@@ -7,85 +5,5 @@
点击可展开一个图形按钮菜单
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 不建议动态修改属性,可能会耗损部分性能。
> - 展开菜单暂不支持字体图标,使用图片路径时建议使用绝对路径,相对路径可能会有问题。
> - 选中状态要通过自己控制,如果不希望有选中状态,不处理 `active` 即可。
> - 展开菜单建议最多显示四个,如果过多对于小屏手机可能会超出屏幕。
### 基本用法
`template` 中使用组件
```html
<template>
<view>
<uni-fab
:pattern="pattern"
:content="content"
:horizontal="horizontal"
:vertical="vertical"
:direction="direction"
@trigger="trigger"
></uni-fab>
</view>
</template>
```
## API
### Fab Props
| 属性名 | 类型 | 默认值 | 说明 |
| :-: | :-: | :-: | :-: |
| pattern | Object | - | 可选样式配置项 |
| horizontal| String | 'left' | 水平对齐方式。`left`:左对齐,`right`:右对齐 |
| vertical | String | 'bottom' | 垂直对齐方式。`bottom`:下对齐,`top`:上对齐 |
| direction | String | 'horizontal' | 展开菜单显示方式。`horizontal`:水平显示,`vertical`:垂直显示 |
| popMenu | Boolean | true | 是否使用弹出菜单 |
| content | Array | - | 展开菜单内容配置项 |
**pattern配置项:**
| 参数 | 类型 | 默认值 | 说明 |
| :-: | :-: | :-: | :-: |
| color | String | #3c3e49 | 文字默认颜色 |
| selectedColor | String | #007AFF | 文字选中时的颜色 |
| backgroundColor | String | #ffffff | 背景色 |
| buttonColor | String | #3c3e49 | 按钮背景色 |
**content配置项:**
| 参数 | 类型 | 说明 |
| :-: | :-: | :-: | :-: |
| iconPath | String | 图片路径 |
| selectedIconPath | String | 选中后图片路径|
| text | String | 文字 |
| active | Boolean | 是否选中当前 |
### Fab Events
| 参数 | 类型 | 说明 |
| :-: | :-: | :-: |
| @trigger | Function | 展开菜单点击事件,返回点击信息|
| @fabClick | Function | 悬浮按钮点击事件 |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab](https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab)
\ No newline at end of file
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-fab)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 1.0.2(2022-07-04)
- 修复 在uni-forms下样式不生效的bug
## 1.0.1(2021-11-23)
- 修复 参数为对象的情况下,url在某些情况显示错误的bug
## 1.0.0(2021-11-19)
......
......@@ -84,6 +84,9 @@
uploadImage,
uploadFile
},
options: {
virtualHost: true
},
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
props: {
// #ifdef VUE3
......@@ -278,7 +281,7 @@
files.push(Object.assign({}, v))
}
})
this.uploadFiles(files)
return this.uploadFiles(files)
},
async setValue(newVal, oldVal) {
const newData = async (v) => {
......@@ -416,11 +419,12 @@
*/
uploadFiles(files) {
files = [].concat(files)
uploadCloudFiles.call(this, files, 5, res => {
return uploadCloudFiles.call(this, files, 5, res => {
this.setProgress(res, res.index, true)
})
.then(result => {
this.setSuccessAndError(result)
return result;
})
.catch(err => {
console.log(err)
......@@ -606,7 +610,9 @@
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
width: 100%;
/* #endif */
flex: 1;
}
.uni-file-picker__header {
......
{
"id": "uni-file-picker",
"displayName": "uni-file-picker 文件选择上传",
"version": "1.0.1",
"version": "1.0.2",
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
"keywords": [
"uni-ui",
......
## 1.4.8(2022-08-23)
- 优化 根据 rules 自动添加 required 的问题
## 1.4.7(2022-08-22)
- 修复 item 未设置 require 属性,rules 设置 require 后,星号也显示的 bug,详见:[https://ask.dcloud.net.cn/question/151540](https://ask.dcloud.net.cn/question/151540)
## 1.4.6(2022-07-13)
- 修复 model 需要校验的值没有声明对应字段时,导致第一次不触发校验的bug
## 1.4.5(2022-07-05)
- 新增 更多表单示例
- 优化 子表单组件过期提示的问题
- 优化 子表单组件uni-datetime-picker、uni-data-select、uni-data-picker的显示样式
## 1.4.4(2022-07-04)
- 更新 删除组件日志
## 1.4.3(2022-07-04)
- 修复 由 1.4.0 引发的 label 插槽不生效的bug
## 1.4.2(2022-07-04)
- 修复 子组件找不到 setValue 报错的bug
## 1.4.1(2022-07-04)
- 修复 uni-data-picker 在 uni-forms-item 中报错的bug
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.4.0(2022-06-30)
- 【重要】组件逻辑重构,部分用法用旧版本不兼容,请注意兼容问题
- 【重要】组件使用 Provide/Inject 方式注入依赖,提供了自定义表单组件调用 uni-forms 校验表单的能力
- 新增 model 属性,等同于原 value/modelValue 属性,旧属性即将废弃
- 新增 validateTrigger 属性的 blur 值,仅 uni-easyinput 生效
- 新增 onFieldChange 方法,可以对子表单进行校验,可替代binddata方法
- 新增 子表单的 setRules 方法,配合自定义校验函数使用
- 新增 uni-forms-item 的 setRules 方法,配置动态表单使用可动态更新校验规则
- 优化 动态表单校验方式,废弃拼接name的方式
## 1.3.3(2022-06-22)
- 修复 表单校验顺序无序问题
## 1.3.2(2021-12-09)
......
<template>
<view class="uni-forms" :class="{ 'uni-forms--top': !border }">
<form @submit.stop="submitForm" @reset="resetForm">
<view class="uni-forms">
<form>
<slot></slot>
</form>
</view>
</template>
<script>
import Validator from './validate.js';
import {
deepCopy,
getValue,
isRequiredField,
setDataValue,
getDataValue,
realName,
isRealName,
rawData,
isEqual
} from './utils.js'
// #ifndef VUE3
// 后续会慢慢废弃这个方法
import Vue from 'vue';
Vue.prototype.binddata = function(name, value, formName) {
if (formName) {
......@@ -26,18 +40,15 @@
}
};
// #endif
import Validator from './validate.js';
/**
* Forms 表单
* @description 由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据
* @tutorial https://ext.dcloud.net.cn/plugin?id=2773
* @property {Object} rules 表单校验规则
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit
* @property {String} validateTrigger = [bind|submit|blur] 校验触发器方式 默认 submit
* @value bind 发生变化时触发
* @value submit 提交时触发
* @value blur 失去焦点时触发
* @property {String} labelPosition = [top|left] label 位置 默认 left
* @value top 顶部显示 label
* @value left 左侧显示 label
......@@ -51,25 +62,34 @@
* @value toast 错误信息toast显示
* @value modal 错误信息modal显示
* @event {Function} submit 提交时触发
* @event {Function} validate 校验结果发生变化触发
*/
export default {
name: 'uniForms',
components: {},
emits:['input','reset','validate','submit'],
emits: ['validate', 'submit'],
options: {
virtualHost: true
},
props: {
// 即将弃用
value: {
type: Object,
default () {
return {};
return null;
}
},
// 替换 value 属性
// vue3 替换 value 属性
modelValue: {
type: Object,
default () {
return {};
return null;
}
},
// 1.4.0 开始将不支持 v-model ,且废弃 value 和 modelValue
model: {
type: Object,
default () {
return null;
}
},
// 表单校验规则
......@@ -79,58 +99,68 @@
return {};
}
},
// 校验触发器方式,默认 关闭
//校验错误信息提示方式 默认 undertext 取值 [undertext|toast|modal]
errShowType: {
type: String,
default: 'undertext'
},
// 校验触发器方式 默认 bind 取值 [bind|submit]
validateTrigger: {
type: String,
default: ''
default: 'submit'
},
// label 位置,可选值 top/left
// label 位置,默认 left 取值 top/left
labelPosition: {
type: String,
default: 'left'
},
// label 宽度,单位 px
// label 宽度
labelWidth: {
type: [String, Number],
default: ''
},
// label 居中方式,可选值 left/center/right
// label 居中方式,默认 left 取值 left/center/right
labelAlign: {
type: String,
default: 'left'
},
errShowType: {
type: String,
default: 'undertext'
},
border: {
type: Boolean,
default: false
}
},
provide() {
return {
uniForm: this
}
},
data() {
return {
formData: {}
// 表单本地值的记录,不应该与传如的值进行关联
formData: {},
formRules: {}
};
},
computed: {
dataValue() {
if (JSON.stringify(this.modelValue) === '{}') {
return this.value
} else {
return this.modelValue
// 计算数据源变化的
localData() {
const localVal = this.model || this.modelValue || this.value
if (localVal) {
return deepCopy(localVal)
}
return {}
}
},
watch: {
rules(newVal) {
// 如果规则发生变化,要初始化组件
this.init(newVal);
},
labelPosition() {
this.childrens.forEach(vm => {
vm.init()
})
// 监听数据变化 ,暂时不使用,需要单独赋值
// localData: {},
// 监听规则变化
rules: {
handler: function(val, oldVal) {
this.setRules(val)
},
deep: true,
immediate: true
}
},
created() {
......@@ -156,146 +186,132 @@
}
// #endif
// 存放watch 监听数组
this.unwatchs = [];
// 存放子组件数组
this.childrens = [];
// 存放 easyInput 组件
this.inputChildrens = [];
// 存放 dataCheckbox 组件
this.checkboxChildrens = [];
// 存放规则
this.formRules = [];
this.init(this.rules);
// 子组件实例数组
this.childrens = []
// TODO 兼容旧版 uni-data-picker ,新版本中无效,只是避免报错
this.inputChildrens = []
this.setRules(this.rules)
},
// mounted() {
// this.init(this.rules)
// },
methods: {
init(formRules) {
// 判断是否有规则
if (Object.keys(formRules).length === 0) {
try{
// TODO 不影响原始数据
this.formData = JSON.parse(JSON.stringify(this.dataValue))
}catch(e){
//TODO handle the exception
this.formData = {}
}
return
};
this.formRules = formRules;
this.validator = new Validator(formRules);
this.registerWatch();
},
// 监听 watch
registerWatch() {
// 取消监听,避免多次调用 init 重复执行 $watch
this.unwatchs.forEach(v => v());
this.childrens.forEach((v) => {
v.init()
})
// watch 每个属性 ,需要知道具体那个属性发变化
Object.keys(this.dataValue).forEach(key => {
let watch = this.$watch(
'dataValue.' + key,
value => {
if (!value){
this.formData[key] = this._getValue(key,value);
return
}
// 如果是对象 ,则平铺内容
if (value.toString() === '[object Object]') {
for (let i in value) {
let name = `${key}[${i}]`;
this.formData[name] = this._getValue(name, value[i]);
}
} else {
this.formData[key] = this._getValue(key, value);
}
},
{
deep: true,
immediate: true
}
);
this.unwatchs.push(watch);
});
},
/**
* 公开给用户使用
* 设置验规则
* @param {Object} formRules
* 外部调用方法
* 设置规则 ,主要用于小程序自定义检验规则
* @param {Array} rules 规则源数据
*/
setRules(formRules) {
this.init(formRules);
setRules(rules) {
// TODO 有可能子组件合并规则的时机比这个要早,所以需要合并对象 ,而不是直接赋值,可能会被覆盖
this.formRules = Object.assign({}, this.formRules, rules)
// 初始化校验函数
this.validator = new Validator(rules);
},
/**
* 公开给用户使用
* 设置自定义表单组件 value 值
* @param {String} name 字段名称
* @param {String} value 字段值
* 外部调用方法
* 设置数据,用于设置表单数据,公开给用户使用 , 不支持在动态表单中使用
* @param {Object} key
* @param {Object} value
*/
setValue(name, value, callback) {
let example = this.childrens.find(child => child.name === name);
setValue(key, value) {
let example = this.childrens.find(child => child.name === key);
if (!example) return null;
value = this._getValue(example.name, value);
this.formData[name] = value;
example.val = value;
return example.triggerCheck(value, callback);
this.formData[key] = getValue(key, value, (this.formRules[key] && this.formRules[key].rules) || [])
return example.onFieldChange(this.formData[key]);
},
/**
* 外部调用方法
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
* @param {Array} keepitem 保留不参与校验的字段
* @param {type} callback 方法回调
*/
validate(keepitem, callback) {
return this.checkAll(this.formData, keepitem, callback);
},
/**
* 表单重置
* @param {Object} event
* 外部调用方法
* 部分表单校验
* @param {Array|String} props 需要校验的字段
* @param {Function} 回调函数
*/
resetForm(event) {
validateField(props = [], callback) {
props = [].concat(props);
let invalidFields = {};
this.childrens.forEach(item => {
item.errMsg = '';
const inputComp = this.inputChildrens.find(child => child.rename === item.name);
if (inputComp) {
inputComp.errMsg = '';
// fix by mehaotian 不触发其他组件的 setValue
inputComp.is_reset = true
inputComp.$emit('input', inputComp.multiple ? [] : '');
inputComp.$emit('update:modelValue', inputComp.multiple ? [] : '');
const name = realName(item.name)
if (props.indexOf(name) !== -1) {
invalidFields = Object.assign({}, invalidFields, {
[name]: this.formData[name]
});
}
});
return this.checkAll(invalidFields, [], callback);
},
/**
* 外部调用方法
* 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
* @param {Array|String} props 需要移除校验的字段 ,不填为所有
*/
clearValidate(props = []) {
props = [].concat(props);
this.childrens.forEach(item => {
if (item.name) {
this.formData[item.name] = this._getValue(item.name, '');
if (props.length === 0) {
item.errMsg = '';
} else {
const name = realName(item.name)
if (props.indexOf(name) !== -1) {
item.errMsg = '';
}
}
});
this.$emit('reset', event);
},
/**
* 触发表单校验,通过 @validate 获取
* @param {Object} validate
* 外部调用方法 ,即将废弃
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
* @param {Array} keepitem 保留不参与校验的字段
* @param {type} callback 方法回调
*/
validateCheck(validate) {
if (validate === null) validate = null;
this.$emit('validate', validate);
submit(keepitem, callback, type) {
for (let i in this.dataValue) {
const itemData = this.childrens.find(v => v.name === i);
if (itemData) {
if (this.formData[i] === undefined) {
this.formData[i] = this._getValue(i, this.dataValue[i]);
}
}
}
if (!type) {
console.warn('submit 方法即将废弃,请使用validate方法代替!');
}
return this.checkAll(this.formData, keepitem, callback, 'submit');
},
/**
* 校验所有或者部分表单
*/
async validateAll(invalidFields, type, keepitem, callback) {
// 校验所有
async checkAll(invalidFields, keepitem, callback, type) {
// 不存在校验规则 ,则停止校验流程
if (!this.validator) return
let childrens = []
// 处理参与校验的item实例
for (let i in invalidFields) {
const item = this.childrens.find(v => v.name === i)
const item = this.childrens.find(v => realName(v.name) === i)
if (item) {
childrens.push(item)
}
}
// 如果validate第一个参数是funciont ,那就走回调
if (!callback && typeof keepitem === 'function') {
callback = keepitem;
}
let promise;
// 如果不存在回调,那么使用 Promise 方式返回
if (!callback && typeof callback !== 'function' && Promise) {
promise = new Promise((resolve, reject) => {
callback = function(valid, invalidFields) {
......@@ -305,47 +321,39 @@
}
let results = [];
let newFormData = {};
if (this.validator) {
for (let key in childrens) {
const child = childrens[key];
let name = child.isArray ? child.arrayField : child.name;
if (child.isArray) {
if (child.name.indexOf('[') !== -1 && child.name.indexOf(']') !== -1) {
const fieldData = child.name.split('[');
const fieldName = fieldData[0];
const fieldValue = fieldData[1].replace(']', '');
if (!newFormData[fieldName]) {
newFormData[fieldName] = {};
}
newFormData[fieldName][fieldValue] = this._getValue(name, invalidFields[name]);
}
} else {
newFormData[name] = this._getValue(name, invalidFields[name]);
}
const result = await child.triggerCheck(invalidFields[name], true);
if (result) {
results.push(result);
if (this.errShowType === 'toast' || this.errShowType === 'modal') break;
}
// 避免引用错乱 ,建议拷贝对象处理
let tempFormData = JSON.parse(JSON.stringify(invalidFields))
// 所有子组件参与校验,使用 for 可以使用 awiat
for (let i in childrens) {
const child = childrens[i]
let name = realName(child.name);
const result = await child.onFieldChange(tempFormData[name]);
if (result) {
results.push(result);
// toast ,modal 只需要执行第一次就可以
if (this.errShowType === 'toast' || this.errShowType === 'modal') break;
}
} else {
newFormData = invalidFields
}
if (Array.isArray(results)) {
if (results.length === 0) results = null;
}
if (Array.isArray(keepitem)) {
keepitem.forEach(v => {
newFormData[v] = this.dataValue[v];
let vName = realName(v);
let value = getDataValue(v, this.localData)
if (value !== undefined) {
tempFormData[vName] = value
}
});
}
// TODO submit 即将废弃
if (type === 'submit') {
this.$emit('submit', {
detail: {
value: newFormData,
value: tempFormData,
errors: results
}
});
......@@ -353,129 +361,37 @@
this.$emit('validate', results);
}
callback && typeof callback === 'function' && callback(results, newFormData);
// const resetFormData = rawData(tempFormData, this.localData, this.name)
let resetFormData = {}
resetFormData = rawData(tempFormData, this.name)
callback && typeof callback === 'function' && callback(results, resetFormData);
if (promise && callback) {
return promise;
} else {
return null;
}
},
submitForm() {},
/**
* 外部调用方法
* 手动提交校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
*/
submit(keepitem, callback, type) {
for (let i in this.dataValue) {
const itemData = this.childrens.find(v => v.name === i);
if (itemData) {
if (this.formData[i] === undefined) {
this.formData[i] = this._getValue(i, this.dataValue[i]);
}
}
}
if (!type) {
console.warn('submit 方法即将废弃,请使用validate方法代替!');
}
return this.validateAll(this.formData, 'submit', keepitem, callback);
},
/**
* 外部调用方法
* 校验表单
* 对整个表单进行校验的方法,参数为一个回调函数。
*/
validate(keepitem, callback) {
return this.submit(keepitem, callback, true);
},
/**
* 部分表单校验
* @param {Object} props
* @param {Object} cb
*/
validateField(props, callback) {
props = [].concat(props);
let invalidFields = {};
this.childrens.forEach(item => {
if (props.indexOf(item.name) !== -1) {
invalidFields = Object.assign({}, invalidFields, {
[item.name]: this.formData[item.name]
});
}
});
return this.validateAll(invalidFields, 'submit', [], callback);
},
/**
* 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
* 返回validate事件
* @param {Object} result
*/
resetFields() {
this.resetForm();
validateCheck(result) {
this.$emit('validate', result);
},
/**
* 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果
*/
clearValidate(props) {
props = [].concat(props);
this.childrens.forEach(item => {
const inputComp = this.inputChildrens.find(child => child.rename === item.name);
if (props.length === 0) {
item.errMsg = '';
if (inputComp) {
inputComp.errMsg = '';
}
} else {
if (props.indexOf(item.name) !== -1) {
item.errMsg = '';
if (inputComp) {
inputComp.errMsg = '';
}
}
}
});
},
/**
* 把 value 转换成指定的类型
* @param {Object} key
* @param {Object} value
*/
_getValue(key, value) {
const rules = (this.formRules[key] && this.formRules[key].rules) || [];
const isRuleNum = rules.find(val => val.format && this.type_filter(val.format));
const isRuleBool = rules.find(val => (val.format && val.format === 'boolean') || val.format === 'bool');
// 输入值为 number
if (isRuleNum) {
value = isNaN(value) ? value : value === '' || value === null ? null : Number(value);
}
// 简单判断真假值
if (isRuleBool) {
value = !value ? false : true;
}
return value;
},
/**
* 过滤数字类型
* @param {Object} format
*/
type_filter(format) {
return format === 'int' || format === 'double' || format === 'number' || format === 'timestamp';
}
_getValue: getValue,
_isRequiredField: isRequiredField,
_setDataValue: setDataValue,
_getDataValue: getDataValue,
_realName: realName,
_isRealName: isRealName,
_isEqual: isEqual
}
};
</script>
<style lang="scss" >
.uni-forms {
// overflow: hidden;
// padding: 10px 15px;
}
.uni-forms--top {
// padding: 10px 15px;
// padding-top: 22px;
}
<style lang="scss">
.uni-forms {}
</style>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-link](https://uniapp.dcloud.io/component/uniui/uni-link)
## 1.1.7(2021-11-08)
## 0.0.7(2021-09-03)
- 修复 在 nvue 下不显示的 bug
## 0.0.6(2021-07-30)
- 新增 支持自定义插槽
## 0.0.5(2021-06-21)
- 新增 download 属性,H5平台下载文件名
## 0.0.4(2021-05-12)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册