Commit d8df8766 authored by wlxuqu's avatar wlxuqu

1. 新增uni-app生态最强表单验证Form、Form-item,Input组件

2. 新增Select列选择器,可以单列,多列,多列联动选择
3. 新增Calendar日历组件,可以单选,范围选择日期等
4. 新增BackTop返回顶部组件
5. Icon组件新增支持图片模式,新增custom-style参数
6. Collapse折叠面板新增item-style参数,修复head-style,body-style可能无效的问题
7. 新增对象深度克隆JS工具库方法,使用方式为"this.$u.deepClone(object)"
8. 新增对象深度合并JS工具库方法,使用方式为"this.$u.deepMerge(target, source)"
9. 新增仿微信个人中心首页模板
10. 新增结合自定义键盘及验证码输入框组件的支付模板
11. 优化城市选择模板的逻辑和动画
12. 优化Radio单选框点击图标部分可能不灵敏的问题
13. 优化Checkbox单选框点击图标部分可能不灵敏的问题
14. 优化SwipeAction组件按钮可能闪一下的问题
15. 优化Http请求头信息可能由于浅合并导致的问题,修复响应拦截返回false依然进入then回调的问题
16. 优化Checkbox组件,可以无需搭配Checkbox-group而独立使用
17. 移除演示项目根目录/static中的无用图片资源,转用线上CDN资源
18. 修复Icon图标在头条,百度小程序上无法显示的问题
19. 修复MessageInput验证码输入框组件可能会在右边显示输入内容的问题
20. 优化u-border基础类的边框特殊场景可能会有边框缺失的问题
21. 优化ActionSheet的取消按钮提示,由cancel-text提供
22. 移除Model组件的content-slot组件,改由组件内部判断,原功能不受影响
23. 修复NoNetwork组件会导致状态栏文字变化的问题
24. Swiper组件新增bg-color设置背景颜色的参数
25. 优化Tabs组件动态修改list参数长度对内部Current索引的判断和修改
26. 优化Timeline组件左边图标的z-index层级的问题
parent e66f6704
......@@ -2,14 +2,14 @@
"easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
"condition": { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [{
"name": "test", //模式名称
"path": "pages/componentsA/calendar/index", //启动页面,必选
"query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到
}]
},
// "condition": { //模式配置,仅开发期间生效
// "current": 0, //当前激活的模式(list 的索引项)
// "list": [{
// "name": "test", //模式名称
// "path": "pages/componentsA/form/index", //启动页面,必选
// "query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到
// }]
// },
"pages": [
// 演示-组件
{
......@@ -218,6 +218,28 @@
{
"root": "pages/template",
"pages": [
// wxCenter 仿微信个人中心
{
"path": "wxCenter/index",
"style": {
"navigationBarTitleText": "wxCenter 仿微信个人中心",
"navigationStyle": "custom"
}
},
// keyboardPay 自定义键盘支付
{
"path": "keyboardPay/index",
"style": {
"navigationBarTitleText": "keyboardPay 自定义键盘支付"
}
},
// // douyin 仿抖音
// {
// "path": "douyin/index",
// "style": {
// "navigationBarTitleText": "douyin 仿抖音"
// }
// },
// mallMenu商城分类
{
"path": "mallMenu/index2",
......@@ -306,6 +328,20 @@
{
"root": "pages/library",
"pages": [
// deepClone-对象深度克隆
{
"path": "deepClone/index",
"style": {
"navigationBarTitleText": "deepClone-对象深度克隆"
}
},
// deepMerge-对象深度合并
{
"path": "deepMerge/index",
"style": {
"navigationBarTitleText": "deepMerge-对象深度合并"
}
},
// getRect-元素节点
{
"path": "getRect/index",
......@@ -450,6 +486,13 @@
{
"root": "pages/componentsA",
"pages": [
// backTop-返回顶部
{
"path": "backTop/index",
"style": {
"navigationBarTitleText": "backTop-返回顶部"
}
},
// calendar-日历
{
"path": "calendar/index",
......@@ -680,12 +723,6 @@
"style": {
"navigationBarTitleText": "upload-上传"
}
}, // validation表单验证
{
"path": "validation/index",
"style": {
"navigationBarTitleText": "validation-表单验证"
}
}, // waterfall瀑布流
{
"path": "waterfall/index",
......
<template>
<view class="u-demo">
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-no-demo-here">滚动页面即可在右下角看到返回顶部的按钮</view>
</view>
<u-back-top :scrollTop="scrollTop" :mode="mode"
:bottom="bottom" :right="right" :top="top" :icon="icon" :custom-style="customStyle"
:icon-style="iconStyle" :tips="tips"
>
</u-back-top>
</view>
<view class="u-config-wrap">
<view class="u-config-title u-border-bottom">
参数配置
</view>
<view class="u-config-item">
<view class="u-item-title">模式</view>
<u-subsection vibrateShort :list="['圆形', '方形']" @change="modeChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">组件位置</view>
<u-subsection vibrateShort :list="['默认', '自定义']" @change="positionChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">显示组件的滚动条距离</view>
<u-subsection vibrateShort current="1" :list="['200', '400', '600']" @change="scrollTopChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">自定义样式</view>
<u-subsection vibrateShort current="1" :list="['是', '否']" @change="styleChange"></u-subsection>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
scrollTop: 0,
mode: 'circle',
bottom: 200,
right: 40,
top: 400,
icon: 'arrow-upward',
iconStyle: {
color: '#909399',
fontSize: '38rpx'
},
customStyle: {},
tips: ''
}
},
methods: {
modeChange(index) {
this.mode = !index ? 'circle' : 'square';
},
positionChange(index) {
if(index == 0) {
this.bottom = 200;
this.right = 40;
} else {
this.bottom = 400;
this.right = 80;
}
},
scrollTopChange(index) {
this.top = [200, 400, 600][index];
},
styleChange(index) {
if(index == 0) {
this.icon = 'arrow-up';
this.iconStyle = {
color: '#2979ff',
fontSize: '34rpx'
};
this.customStyle = {
backgroundColor: '#a0cfff',
color: '#2979ff'
};
this.tips = '顶部';
} else {
this.icon = 'arrow-upward';
this.iconStyle = {
color: '#909399',
fontSize: '38rpx'
};
this.customStyle = {};
this.tips = '';
}
}
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
}
}
</script>
<style lang="scss" scoped>
.u-demo {
height: 200vh;
}
</style>
......@@ -42,7 +42,7 @@
export default {
data() {
return {
show: true,
show: false,
mode: 'range',
arrowType: 1,
minDate: "1920-01-01",
......
......@@ -3,6 +3,9 @@
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-no-demo-here">
滚动页面,在由下角即可看到返回顶部按钮
</view>
<u-empty :mode="mode">
<u-button v-if="slot" slot="bottom" size="medium">
slot按钮
......
<template>
<view class="wrap">
<u-form :model="model" :rules="rules" ref="uForm">
<u-form-item left-icon="map" label-width="120" :label-position="labelPosition" label="姓名" prop="name">
<u-form :model="model" :rules="rules" ref="uForm" :errorType="errorType">
<u-form-item :leftIconStyle="{color: '#888', fontSize: '32rpx'}" left-icon="account" label-width="120" :label-position="labelPosition" label="姓名" prop="name">
<u-input :border="border" placeholder="请输入姓名" v-model="model.name" type="text"></u-input>
</u-form-item>
<u-form-item :label-position="labelPosition" label="性别" prop="sex">
......@@ -11,10 +11,10 @@
<u-input type="textarea" :border="border" placeholder="请填写简介" v-model="model.intro" />
</u-form-item>
<u-form-item :label-position="labelPosition" label="密码" prop="password">
<u-input :border="border" type="text" :password="true" v-model="model.password" placeholder="请输入密码"></u-input>
<u-input :border="border" type="password" :password="true" v-model="model.password" placeholder="请输入密码"></u-input>
</u-form-item>
<u-form-item :label-position="labelPosition" label="确认密码" label-width="150" prop="rePassword">
<u-input :border="border" type="text" :password="true" v-model="model.rePassword" placeholder="请确认密码"></u-input>
<u-input :border="border" type="password" :password="true" v-model="model.rePassword" placeholder="请确认密码"></u-input>
</u-form-item>
<u-form-item :label-position="labelPosition" label="水果品种" label-width="150" prop="likeFruit">
<u-checkbox-group @change="checkboxGroupChange" :width="radioCheckWidth" :wrap="radioCheckWrap">
......@@ -32,13 +32,20 @@
<u-form-item :label-position="labelPosition" label="商品类型" prop="goodsType" label-width="150">
<u-input :border="border" type="select" :select-open="selectShow" v-model="model.goodsType" placeholder="请选择商品类型" @click="selectShow = true"></u-input>
</u-form-item>
<u-form-item :label-position="labelPosition" label="手机号码" prop="phone" label-width="150">
<u-form-item :rightIconStyle="{color: '#888', fontSize: '32rpx'}" right-icon="kefu-ermai" :label-position="labelPosition" label="手机号码" prop="phone" label-width="150">
<u-input :border="border" placeholder="请输入手机号" v-model="model.phone" type="number"></u-input>
</u-form-item>
<u-form-item :label-position="labelPosition" label="验证码" prop="code" label-width="150">
<u-input :border="border" placeholder="请输入验证码" v-model="model.code" type="text"></u-input>
<u-button slot="right" type="success" size="mini" @click="getCode">{{codeTips}}</u-button>
</u-form-item>
<!-- 此处switch的slot为right,如果不填写slot名,也即<u-switch v-model="model.remember"></u-switch>,将会左对齐 -->
<u-form-item :label-position="labelPosition" label="记住密码" prop="remember" label-width="150">
<u-switch v-model="model.remember" slot="right"></u-switch>
</u-form-item>
<u-form-item :label-position="labelPosition" label="上传图片" prop="photo" label-width="150">
<u-upload width="160"></u-upload>
</u-form-item>
</u-form>
<view class="agreement">
<u-checkbox v-model="check" @change="checkboxChange"></u-checkbox>
......@@ -61,23 +68,15 @@
</view>
<view class="u-config-item">
<view class="u-item-title">边框</view>
<u-subsection vibrateShort current="1" :list="['显示', '隐藏']" @change="borderChange"></u-subsection>
<u-subsection vibrateShort :current="borderCurrent" :list="['显示', '隐藏']" @change="borderChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">radio、checkbox样式</view>
<u-subsection vibrateShort :list="['自适应', '换行', '50%宽度']" @change="radioCheckboxChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">打乱顺序</view>
<u-subsection vibrateShort :current="1" :list="['是', '否']" @change="randomChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">上方工具条</view>
<u-subsection vibrateShort :list="['显示', '隐藏']" @change="tooltipChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">是否显示遮罩</view>
<u-subsection vibrateShort :list="['显示', '隐藏']" @change="maskChange"></u-subsection>
<view class="u-item-title">错误提示方式</view>
<u-subsection vibrateShort :list="['文字', '下划线', '输入框', '下划线+文字']" @change="errorChange"></u-subsection>
</view>
</view>
</view>
......@@ -101,7 +100,8 @@ export default {
code: '',
password: '',
rePassword: '',
remember: false,
photo: ''
},
selectList: [
{
......@@ -128,7 +128,7 @@ export default {
min: 3,
max: 5,
message: '姓名长度在3到5个字符',
trigger: 'change,blur',
trigger: ['change','blur'],
},
{
validator: (rule, value, callback) => {
......@@ -137,7 +137,7 @@ export default {
},
message: '姓名必须为中文',
// 触发器可以同时用blur和change,二者之间用英文逗号隔开
trigger: 'change,blur',
trigger: ['change','blur'],
}
],
sex: [
......@@ -197,7 +197,7 @@ export default {
{
required: true,
message: '请输入手机号',
trigger: 'change,blur',
trigger: ['change','blur'],
},
{
validator: (rule, value, callback) => {
......@@ -206,46 +206,46 @@ export default {
},
message: '手机号码不正确',
// 触发器可以同时用blur和change,二者之间用英文逗号隔开
trigger: 'change,blur',
trigger: ['change','blur'],
}
],
code: [
{
required: true,
message: '请输入验证码',
trigger: 'change,blur',
trigger: ['change','blur'],
},
{
type: 'number',
message: '验证码只能为数字',
trigger: 'change,blur',
trigger: ['change','blur'],
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'change,blur',
trigger: ['change','blur'],
},
{
// 正则不能含有两边的引号
pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]+\S{6,12}$/,
message: '需同时含有字母和数字,长度在6-12之间',
trigger: 'change,blur',
trigger: ['change','blur'],
}
],
rePassword: [
{
required: true,
message: '请重新输入密码',
trigger: 'change,blur',
trigger: ['change','blur'],
},
{
validator: (rule, value, callback) => {
return value === this.model.password;
},
message: '两次输入的密码不相等',
trigger: 'change,blur',
trigger: ['change','blur'],
}
],
},
......@@ -315,12 +315,16 @@ export default {
radioCheckWrap: false,
labelPosition: 'left',
codeTips: '',
errorType: ['message'],
};
},
onLoad() {
},
computed: {
borderCurrent() {
return this.border ? 0 : 1;
}
},
onReady() {
this.$refs.uForm.setRules(this.rules);
......@@ -338,6 +342,7 @@ export default {
},
// 点击actionSheet回调
actionSheetCallback(index) {
uni.hideKeyboard();
this.model.sex = this.actionSheetList[index].text;
},
// checkbox选择发生变化
......@@ -402,6 +407,15 @@ export default {
this.$u.toast('倒计时结束后再发送');
}
},
errorChange(index) {
if(index == 0) this.errorType = ['message'];
if(index == 1) this.errorType = ['border-bottom'];
if(index == 2) {
this.errorType = ['border'];
this.border = true;
}
if(index == 3) this.errorType = ['message', 'border-bottom'];
}
}
};
</script>
......
......@@ -120,7 +120,7 @@ export default {
if (this.params.year) this.input += e.year;
if (this.params.month) this.input += '-' + e.month;
if (this.params.day) this.input += '-' + e.day;
if (this.params.hour) this.input += ' ' + e.day;
if (this.params.hour) this.input += ' ' + e.hour;
if (this.params.minute) this.input += ':' + e.minute;
if (this.params.second) this.input += ':' + e.second;
} else if (this.mode == 'region') {
......
......@@ -46,7 +46,7 @@
export default {
data() {
return {
list: [
list1: [
{
id: 1,
title: '长安回望绣成堆,山顶千门次第开,一骑红尘妃子笑,无人知是荔枝来',
......@@ -66,6 +66,7 @@ export default {
show: false,
}
],
list: [],
disabled: false,
btnWidth: 180,
show: false,
......@@ -85,6 +86,11 @@ export default {
]
};
},
onLoad() {
setTimeout(() => {
this.list = this.list1;
}, 2000)
},
methods: {
disabledChange(index) {
this.disabled = index == 0 ? true : false;
......
<template>
<view class="wrap">
<form @submit="submit">
<view class="item u-border-bottom">
<view class="label">
姓名
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入姓名" type="text" name="name" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
金额
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入金额,最多2位小数" type="text" name="amount" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
邮箱
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入邮箱" type="text" name="email" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
身份证
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入身份证号" type="text" name="idCard" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
最大值
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入小于99的数值" type="text" name="max" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
数字字母
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入数字和字母" type="text" name="enOrNum" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
手机号
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入手机号" type="text" name="tel" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
车牌号
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入车牌号" type="text" name="carNo" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
数值
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入数值" type="text" name="digits" value="" />
</view>
</view>
<view class="item u-border-bottom">
<view class="label">
日期
</view>
<view class="field">
<input placeholder-class="placeholder-class" placeholder="请输入有效日期" type="text" name="date" value="" />
</view>
</view>
<u-toast ref="uToast"></u-toast>
<button form-type="submit">提交</button>
</form>
</view>
</template>
<script>
import Uvalidation from "uview-ui/libs/validation/validation.js";
export default {
data() {
return {
}
},
onLoad() {
this.initValidation();
},
methods: {
initValidation() {
// 规则
const rules = {
name: {
required: true,
},
amount: {
required: true,
amount: true,
},
email: {
required: true,
email: true
},
idCard: {
required: true,
idCard: true
},
max: {
required: true,
max: true
},
enOrNum: {
required: true,
enOrNum: true
},
tel: {
required: true,
tel: true
},
carNo: {
required: true,
carNo: true
},
digits: {
required: true,
digits: true
},
date: {
required: true,
date: true
}
}
// 提示
const messages = {
// name: {
// required: '请输入姓名',
// }
}
// 校验规则
this.Uvalidation = new Uvalidation(rules, messages);
this.Uvalidation.addMethod('assistance', (value) => {
return (value.length >= 1 && value.length <= 2)
}, '请勾选1-2个敲码助手')
},
submit(e) {
let params = e.detail.value;
if (!this.Uvalidation.checkForm(params)) {
//console.log(this.Uvalidation.errorList);
const error = this.Uvalidation.errorList[0].msg;
// 可以自定义提示
this.$refs.uToast.show({
type: 'error',
title: error,
})
return false
} else {
console.log('提交成功!');
}
}
}
}
</script>
<style lang="scss" scoped>
.wrap {
padding: 24rpx;
}
.item {
display: flex;
align-items: center;
margin: 30rpx 0;
font-size: 30rpx;
color: $u-main-color;
padding-bottom: 10rpx;
line-height: 1;
.field {
margin-left: 12rpx;
width: 400rpx;
}
}
.placeholder-class {
font-size: 28rpx;
color: $u-light-color;
}
</style>
......@@ -4,11 +4,9 @@
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<u-toast ref="uToast"></u-toast>
<u-collapse event-type="close" :arrow="arrow" :accordion="accordion" @change="change">
<u-collapse :item-style="itemStyle" event-type="close" :arrow="arrow" :accordion="accordion" @change="change">
<u-collapse-item :index="index" @change="itemChange" :title="item.head" v-for="(item, index) in itemList" :key="index">
<view class="">
{{item.body}}
</view>
</u-collapse-item>
</u-collapse>
</view>
......@@ -25,6 +23,10 @@
<view class="u-item-title">右侧箭头</view>
<u-subsection vibrateShort :list="['显示', '隐藏']" @change="arrowChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">自定义样式</view>
<u-subsection vibrateShort current="1" :list="['是', '否']" @change="styleChange"></u-subsection>
</view>
</view>
</view>
</template>
......@@ -56,7 +58,8 @@
}],
accordion: true,
arrow: true,
hoverClass: 'hover2'
hoverClass: 'hover2',
itemStyle: {}
}
},
methods: {
......@@ -66,6 +69,17 @@
arrowChange(index) {
this.arrow = index == 0 ? true : false;
},
styleChange(index) {
if(index == 0) {
this.itemStyle = {
border: '1px solid rgb(230, 230, 230)',
marginTop: '20px',
padding: '0 8rpx'
}
} else {
this.itemStyle = {}
}
},
change(index) {
let str = '';
if(Array.isArray(index)) {
......@@ -82,7 +96,7 @@
})
},
itemChange(e) {
// console.log(e);
console.log(e);
}
}
}
......
<template>
<u-select v-model="show" mode="mutil-column-auto" :list="list" @confirm="confirm"></u-select>
<view class="wrap">
<text>滑动页面,返回顶部按钮将出现在右下角</text>
<u-back-top :scrollTop="scrollTop" :mode="mode" :icon-style="iconStyle"></u-back-top>
</view>
</template>
<script>
export default {
export default {
data() {
return {
show: true,
list: [
{
value: 1,
label: '中国',
children: [
{
value: 2,
label: '广东',
children: [
{
value: 3,
label: '深圳'
},
{
value: 4,
label: '广州'
}
]
},
{
value: 5,
label: '广西',
children: [
{
value: 6,
label: '南宁'
},
{
value: 7,
label: '桂林'
scrollTop: 0,
mode: 'square',
iconStyle: {
fontSize: '32rpx',
color: '#2979ff'
}
]
}
]
},
{
value: 8,
label: '美国',
children: [
{
value: 9,
label: '纽约',
children: [
{
value: 10,
label: '皇后街区'
}
]
}
]
}
]
}
},
methods: {
confirm(e) {
console.log(e);
}
}
onPageScroll(e) {
this.scrollTop = e.scrollTop;
}
};
</script>
<style lang="scss">
.money{
font-size: 80rpx;
color: $u-type-primary;
<style lang="scss" scoped>
.wrap {
height: 200vh;
}
</style>
......@@ -33,14 +33,18 @@ export default [{
{
groupName: '表单组件',
list: [{
path: '/pages/componentsA/form/index',
icon: 'form',
title: 'Form 表单',
}, {
path: '/pages/componentsA/calendar/index',
icon: 'calendar',
title: 'Calendar 日历',
},{
}, {
path: '/pages/componentsA/select/index',
icon: 'select',
title: 'Select 列选择器',
},{
}, {
path: '/pages/componentsA/keyboard/index',
icon: 'keyboard',
title: 'Keyboard 键盘',
......@@ -157,7 +161,7 @@ export default [{
path: '/pages/componentsB/line/index',
icon: 'line',
title: 'Line 线条',
},{
}, {
path: '/pages/componentsB/card/index',
icon: 'card',
title: 'Card 卡片',
......@@ -201,14 +205,18 @@ export default [{
}, {
groupName: '导航组件',
list: [{
path: '/pages/componentsA/backTop/index',
icon: 'backTop',
title: 'BackTop 返回顶部',
},{
path: '/pages/componentsA/navbar/index',
icon: 'navbar',
title: 'Navbar 导航栏',
},{
}, {
path: '/pages/componentsA/tabs/index',
icon: 'tabs',
title: 'Tabs 标签',
},{
}, {
path: '/pages/template/order/index',
icon: 'tabsSwiper',
title: 'TabsSwiper 全屏选项卡',
......
......@@ -22,6 +22,15 @@ export default [
{
groupName: '工具库',
list: [
{
path: 'deepMerge',
icon: 'deepMerge',
title: 'deepMerge 对象深度合并',
},{
path: 'deepClone',
icon: 'deepClone',
title: 'deepClone 对象深度克隆',
},
{
path: 'timeFormat',
icon: 'timeFormat',
......
......@@ -12,6 +12,21 @@ export default [
{
groupName: '页面',
list: [
{
path: '/pages/template/wxCenter/index',
icon: 'wxCenter',
title: 'WxCenter 仿微信个人中心',
},
// {
// path: '/pages/template/douyin/index',
// icon: 'douyin',
// title: 'Douyin 仿抖音',
// },
{
path: '/pages/template/keyboardPay/index',
icon: 'keyboardPay',
title: 'KeyboardPay 自定义键盘支付模板',
},
{
path: '/pages/template/mallMenu/index1',
icon: 'mall_menu_1',
......
<template>
<view class="u-demo">
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-no-demo-here">
源对象为:"{info: {name: 'mary'}}"
</view>
<view class="u-demo-result-line">
{{result}}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
obj: {
info: {
name: 'mary'
}
},
result: ''
}
},
onLoad() {
this.result = this.$u.deepClone(this.obj);
}
}
</script>
<style lang="scss" scoped>
.u-demo {}
</style>
<template>
<view class="u-demo">
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-no-demo-here">
源对象1为:"{info: {name: 'mary'}}"
<view class="">
</view>
源对象2为:"{info: {age: '22'}}"
</view>
<view class="u-demo-result-line">
{{result}}
</view>
</view>
</view>
<view class="u-config-wrap">
<view class="u-config-title u-border-bottom">
参数配置
</view>
<view class="u-config-item">
<view class="u-item-title">模式</view>
<u-subsection vibrateShort :list="['浅拷贝', '深拷贝']" @change="modeChange"></u-subsection>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
obj1: {
info: {
name: 'mary'
}
},
obj2: {
info: {
age: '22'
}
},
// obj1和obj3一样,原因是Object.assign(this.obj1, this.obj2)会修改obj1的值
obj3: {
info: {
name: 'mary'
}
},
result: ''
}
},
onLoad() {
this.result = Object.assign(this.obj1, this.obj2);
// 重新修改obj1为原来的值
this.obj1 = this.$u.deepClone(this.obj3);
},
methods: {
modeChange(index) {
if(!index) {
this.result = Object.assign(this.obj1, this.obj2);
// 重新修改obj1为原来的值
this.obj1 = this.$u.deepClone(this.obj3);
} else {
this.result = this.$u.deepMerge(this.obj1, this.obj2);
}
}
}
}
</script>
<style lang="scss" scoped>
.u-demo {}
</style>
<template>
<u-popup v-model="value" mode="bottom" :popup="false" :mask="true" :closeable="true" :safe-area-inset-bottom="true"
close-icon-color="#ffffff" :z-index="uZIndex" :maskCloseAble="maskCloseAble" @close="close">
<u-tabs :list="genTabsList" :is-scroll="true" :current="tabsIndex" @change="tabsChange"></u-tabs>
<u-tabs :list="genTabsList" :is-scroll="true" :current="tabsIndex" @change="tabsChange" ref="tabs"></u-tabs>
<view class="area-box">
<view class="u-flex" :class="{ 'change':isChange }">
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group>
<u-cell-item v-for="(item,index) in provinces" :title="item.label" :arrow="false" :index="index" :key="index"
@click="provinceChange">
......@@ -18,7 +18,7 @@
</view>
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group v-show="isChooseP">
<u-cell-item v-for="(item,index) in citys" :title="item.label" :arrow="false" :index="index" :key="index"
@click="cityChange">
......@@ -31,7 +31,7 @@
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true">
<scroll-view :scroll-y="true" style="height: 100%">
<u-cell-group v-show="isChooseC">
<u-cell-item v-for="(item,index) in areas" :title="item.label" :arrow="false" :index="index" :key="index"
@click="areaChange">
......@@ -102,9 +102,6 @@
isChooseA: false, //是否已经选择了区
area: 0, //区级下标
areas: areas[0][0],
tabsList: [{
name: '请选择'
}],
tabsIndex: 0,
}
},
......@@ -143,11 +140,11 @@
},
methods: {
init() {
if (this.areaCode.length) {
if (this.areaCode.length == 3) {
this.setProvince("", this.areaCode[0]);
this.setCity("", this.areaCode[1]);
this.setArea("", this.areaCode[2]);
} else if (this.defaultRegion.length) {
} else if (this.defaultRegion.length == 3) {
this.setProvince(this.defaultRegion[0], "");
this.setCity(this.defaultRegion[1], "");
this.setArea(this.defaultRegion[2], "");
......
<template>
</template>
<script>
</script>
<style>
</style>
<template>
<view>
<view class="u-padding-40">
<u-button type="success" @click="showPop(true)">
<u-icon name="red-packet"></u-icon>
<text class="u-padding-left-10">发送1.00元红包</text>
</u-button>
</view>
<u-keyboard
default="778"
ref="uKeyboard"
mode="number"
:mask="true"
:mask-close-able="false"
:dot-enabled="false"
v-model="show"
:safe-area-inset-bottom="true"
:tooltip="false"
@change="onChange"
@backspace="onBackspace"
>
<view>
<view class="u-text-center u-padding-20 money">
<text>1.00</text>
<text class="u-font-20 u-padding-left-10"></text>
<view class="u-padding-10 close" data-flag="false" @tap="showPop(false)">
<u-icon name="close" color="#333333" size="28"></u-icon>
</view>
</view>
<view class="u-flex u-row-center">
<u-message-input
mode="box"
:maxlength="6"
:dot-fill="true"
v-model="password"
:disabled-keyboard="false"
></u-message-input>
</view>
<view class="u-text-center u-padding-top-10 u-padding-bottom-20 tips">支付键盘</view>
</view>
</u-keyboard>
</view>
</template>
<script>
export default {
data() {
return {
show:false,
password:''
}
},
onLoad() {
console.log(this.$u.config.v)
},
methods: {
onChange(val){
if(this.password.length<6){
this.password += val;
}
if(this.password.length>=6){
this.pay();
}
},
onBackspace(e){
if(this.password.length>0){
this.password = this.password.substring(0,this.password.length-1);
}
},
pay(){
uni.showLoading({
title:'支付中'
})
setTimeout(()=>{
uni.hideLoading();
this.show = false;
uni.showToast({
icon:'success',
title:'支付成功'
})
},2000);
},
showPop(flag = true){
this.password = '';
this.show = flag;
}
}
}
</script>
<style lang="scss">
.money{
font-size: 80rpx;
color: $u-type-warning;
position: relative;
.close{
position: absolute;
top: 20rpx;
right: 20rpx;
line-height: 28rpx;
font-size: 28rpx;
}
}
.tips{
color:$u-tips-color;
}
</style>
<template>
<view>
<u-navbar title="" :border-bottom="false">
<view class="u-flex u-row-right" style="width: 100%;">
<view class="camera u-flex u-row-center">
<u-icon name="camera-fill" color="#000000" size="48"></u-icon>
</view>
</view>
</u-navbar>
<view class="u-flex user-box u-p-l-30 u-p-r-20 u-p-b-30">
<view class="u-m-r-10">
<u-avatar :src="pic" size="140"></u-avatar>
</view>
<view class="u-flex-1">
<view class="u-font-18 u-p-b-20">uView ui</view>
<view class="u-font-14 u-tips-color">微信号:helang_uView</view>
</view>
<view class="u-m-l-10 u-p-10">
<u-icon name="scan" color="#969799" size="28"></u-icon>
</view>
<view class="u-m-l-10 u-p-10">
<u-icon name="arrow-right" color="#969799" size="28"></u-icon>
</view>
</view>
<u-cell-group class="u-m-t-20">
<u-cell-item icon="rmb-circle" title="支付"></u-cell-item>
</u-cell-group>
<u-cell-group class="u-m-t-20">
<u-cell-item icon="star" title="收藏"></u-cell-item>
<u-cell-item icon="photo" title="相册"></u-cell-item>
<u-cell-item icon="coupon" title="卡券"></u-cell-item>
<u-cell-item icon="heart" title="关注"></u-cell-item>
</u-cell-group>
<u-cell-group class="u-m-t-20">
<u-cell-item icon="setting" title="设置"></u-cell-item>
</u-cell-group>
</view>
</template>
<script>
export default {
data() {
return {
pic:'https://uviewui.com/common/logo.png'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style lang="scss">
page{
background-color: #ededed;
}
.camera{
width: 54px;
height: 44px;
&:active{
background-color: #ededed;
}
}
.user-box{
background-color: #fff;
}
</style>
......@@ -30,6 +30,7 @@
* @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
* @property {Number String} z-index z-index值(默认1075)
* @property {String} cancel-text 取消按钮的提示文字
* @event {Function} click 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
......
<template>
<view @tap="backToTop" class="u-back-top" :class="['u-back-top--mode--' + mode]" :style="[{
bottom: bottom + 'rpx',
right: right + 'rpx',
borderRadius: mode == 'circle' ? '10000rpx' : '8rpx',
zIndex: uZIndex,
opacity: opacity
}, customStyle]">
<view class="" v-if="!$slots.default">
<u-icon @click="backToTop" :name="icon" :custom-style="iconStyle"></u-icon>
<view class="u-back-top__tips">
{{tips}}
</view>
</view>
<slot v-else />
</view>
</template>
<script>
export default {
name: 'u-back-top',
props: {
// 返回顶部的形状,circle-圆形,square-方形
mode: {
type: String,
default: 'circle'
},
// 自定义图标
icon: {
type: String,
default: 'arrow-upward'
},
// 提示文字
tips: {
type: String,
default: ''
},
// 返回顶部滚动时间
duration: {
type: [Number, String],
default: 100
},
// 滚动距离
scrollTop: {
type: [Number, String],
default: 0
},
// 距离顶部多少距离显示,单位rpx
top: {
type: [Number, String],
default: 400
},
// 返回顶部按钮到底部的距离,单位rpx
bottom: {
type: [Number, String],
default: 200
},
// 返回顶部按钮到右边的距离,单位rpx
right: {
type: [Number, String],
default: 40
},
// 层级
zIndex: {
type: [Number, String],
default: '9'
},
// 图标的样式,对象形式
iconStyle: {
type: Object,
default() {
return {
color: '#909399',
fontSize: '38rpx'
}
}
},
// 整个组件的样式
customStyle: {
type: Object,
default() {
return {}
}
}
},
watch: {
showBackTop(nVal, oVal) {
// 当组件的显示与隐藏状态发生跳变时,修改组件的层级和不透明度
// 让组件有显示和消失的动画效果,如果用v-if控制组件状态,将无设置动画效果
if(nVal) {
this.uZIndex = this.zIndex;
this.opacity = 1;
} else {
this.uZIndex = -1;
this.opacity = 0;
}
}
},
computed: {
showBackTop() {
// 由于scrollTop为页面的滚动距离,默认为px单位,这里将用于传入的top(rpx)值
// 转为px用于比较,如果滚动条到顶的距离大于设定的距离,就显示返回顶部的按钮
return this.scrollTop > uni.upx2px(this.top);
},
},
data() {
return {
// 不透明度,为了让组件有一个显示和隐藏的过渡动画
opacity: 0,
// 组件的z-index值,隐藏时设置为-1,就会看不到
uZIndex: -1
}
},
methods: {
backToTop() {
uni.pageScrollTo({
scrollTop: 0,
duration: this.duration
});
}
}
}
</script>
<style lang="scss" scoped>
.u-back-top {
width: 80rpx;
height: 80rpx;
position: fixed;
z-index: 9;
display: flex;
flex-direction: column;
justify-content: center;
background-color: #E1E1E1;
color: $u-content-color;
align-items: center;
transition: opacity 0.4s;
&__tips {
font-size: 24rpx;
transform: scale(0.8);
line-height: 1;
}
}
</style>
<template>
<u-popup closeable :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" :border-radius="borderRadius">
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" :border-radius="borderRadius" :closeable="closeable">
<view class="u-calendar">
<view class="u-calendar__header">
<view class="u-calendar__header__text" v-if="!$slots['tool-tip']">
<view class="u-calendar__header__text" v-if="!$slots['tooltip']">
{{toolTip}}
</view>
<slot v-else name="tool-tip" />
<slot v-else name="tooltip" />
</view>
<view class="u-calendar__action u-flex u-row-center">
<view class="u-calendar__action__icon">
<u-icon v-if="changeYear" name="arrow-left-double" :color="yearArrowColor" @click="changeYear(0)"></u-icon>
<u-icon v-if="changeYear" name="arrow-left-double" :color="yearArrowColor" @click="changeYearHandler(0)"></u-icon>
</view>
<view class="u-calendar__action__icon">
<u-icon v-if="changeMonth" name="arrow-left" :color="monthArrowColor" @click="changeMonth(0)"></u-icon>
<u-icon v-if="changeMonth" name="arrow-left" :color="monthArrowColor" @click="changeMonthHandler(0)"></u-icon>
</view>
<view class="u-calendar__action__text">{{ showTitle }}</view>
<view class="u-calendar__action__icon">
<u-icon v-if="changeMonth" name="arrow-right" :color="monthArrowColor" @click="changeMonth(1)"></u-icon>
<u-icon v-if="changeMonth" name="arrow-right" :color="monthArrowColor" @click="changeMonthHandler(1)"></u-icon>
</view>
<view class="u-calendar__action__icon">
<u-icon v-if="changeYear" name="arrow-right-double" :color="yearArrowColor" @click="changeYear(1)"></u-icon>
<u-icon v-if="changeYear" name="arrow-right-double" :color="yearArrowColor" @click="changeYearHandler(1)"></u-icon>
</view>
</view>
<view class="u-calendar__week-day">
......@@ -95,19 +95,19 @@
type: String,
default: 'date'
},
// 可切换最大年份
// 可切换最大年份
maxYear: {
type: Number,
type: [Number, String],
default: 2050
},
// 可切换最小年份
// 可切换最小年份
minYear: {
type: Number,
type: [Number, String],
default: 1950
},
// 最小可选日期(不在范围内日期禁用不可选)
minDate: {
type: String,
type: [Number, String],
default: '1950-01-01'
},
/**
......@@ -116,7 +116,7 @@
* 2030-12-31
* */
maxDate: {
type: String,
type: [Number, String],
default: ''
},
// 弹窗顶部左右两边的圆角值
......@@ -124,47 +124,47 @@
type: [String, Number],
default: 20
},
//月份切换箭头颜色
// 月份切换按钮箭头颜色
monthArrowColor: {
type: String,
default: '#606266'
},
//年份切换箭头颜色
// 年份切换按钮箭头颜色
yearArrowColor: {
type: String,
default: '#909399'
},
//默认日期字体颜色
// 默认日期字体颜色
color: {
type: String,
default: '#303133'
},
//选中|起始结束日期背景色
// 选中|起始结束日期背景色
activeBgColor: {
type: String,
default: '#2979ff'
},
//选中|起始结束日期字体颜色
// 选中|起始结束日期字体颜色
activeColor: {
type: String,
default: '#ffffff'
},
//范围内日期背景色
// 范围内日期背景色
rangeBgColor: {
type: String,
default: 'rgba(41,121,255,0.13)'
},
//范围内日期字体颜色
// 范围内日期字体颜色
rangeColor: {
type: String,
default: '#2979ff'
},
//mode=range时生效,起始日期自定义文案
// mode=range时生效,起始日期自定义文案
startText: {
type: String,
default: '开始'
},
//mode=range时生效,结束日期自定义文案
// mode=range时生效,结束日期自定义文案
endText: {
type: String,
default: '结束'
......@@ -174,16 +174,21 @@
type: String,
default: 'primary'
},
//当前选中日期带选中效果
// 当前选中日期带选中效果
isActiveCurrent: {
type: Boolean,
default: true
},
//切换年月是否触发事件 mode=date时生效
// 切换年月是否触发事件 mode=date时生效
isChange: {
type: Boolean,
default: false
},
// 是否显示右上角的关闭图标
closeable: {
type: Boolean,
default: true
},
// 顶部的提示文字
toolTip: {
type: String,
......@@ -317,7 +322,7 @@
}
return overstep;
},
changeMonth(isAdd) {
changeMonthHandler(isAdd) {
if (isAdd) {
let month = this.month + 1;
let year = month > 12 ? this.year + 1 : this.year;
......@@ -337,7 +342,7 @@
}
}
},
changeYear(isAdd) {
changeYearHandler(isAdd) {
let year = isAdd ? this.year + 1 : this.year - 1;
if (!this.checkRange(year)) {
this.year = year;
......@@ -419,7 +424,7 @@
result: result,
week: weekText,
isToday: isToday,
switch: show //是否是切换年月操作
// switch: show //是否是切换年月操作
});
} else {
if (!this.startDate || !this.endDate) return;
......@@ -495,6 +500,7 @@
&__text {
flex: 1;
text-align: center;
}
}
......
<template>
<view class="u-checkbox" :style="[checkboxStyle]">
<view class="u-checkbox__icon-wrap" @tap="toggle">
<u-icon :class="iconClass" @click="toggle" name="checkbox-mark" :size="iconSize" :color="iconColor" class="u-checkbox__icon" :style="[iconStyle]" />
<u-icon :class="iconClass" name="checkbox-mark" :size="iconSize" :color="iconColor" class="u-checkbox__icon" :style="[iconStyle]" />
</view>
<view class="u-label-class u-checkbox__label" @tap="onClickLabel" :style="{
fontSize: labelSize + 'rpx'
......
<template>
<view class="u-collapse-item">
<view class="u-collapse-item" :style="[itemStyle]">
<view :hover-stay-time="200" class="u-collapse-head" @tap.stop="headClick" :hover-class="hoverClass" :style="[headStyle]">
<view class="u-collapse-title u-line-1" :style="[{ textAlign: align ? align : 'left' },
isShow && activeStyle && !arrow ? activeStyle : '']">
......@@ -12,8 +12,8 @@
</view>
<view class="u-collapse-body" :style="[{
height: isShow ? height + 'px' : '0'
}, bodyStyle]">
<view class="u-collapse-content" :id="elId">
}]">
<view class="u-collapse-content" :id="elId" :style="[bodyStyle]">
<slot></slot>
</view>
</view>
......@@ -84,7 +84,8 @@
height: 0, // body内容的高度
headStyle: {}, // 头部样式,对象形式
bodyStyle: {}, // 主体部分样式
arrowColor: '',
//itemStyle: {}, // 每个item的整体样式
arrowColor: '', // 箭头的颜色
hoverClass: '', // 头部按下时的效果样式类
};
},
......@@ -102,11 +103,15 @@
arrow() {
return this.uCollapse.arrow;
},
itemStyle() {
return this.uCollapse.itemStyle;
}
},
created() {
this.isShow = this.open;
this.nameSync = this.name ? this.name : this.uCollapse.childrens.length;
this.uCollapse.childrens.push(this);
//this.itemStyle = this.uCollapse.itemStyle;
this.headStyle = this.uCollapse.headStyle;
this.bodyStyle = this.uCollapse.bodyStyle;
this.arrowColor = this.uCollapse.arrowColor;
......@@ -127,7 +132,7 @@
this.isShow = !this.isShow;
// 触发本组件的事件
this.$emit('change', {
uni.$emit('change', {
index: this.index,
show: this.isShow
})
......@@ -138,19 +143,11 @@
},
// 查询内容高度
queryRect() {
const query = uni.createSelectorQuery().in(this);
query
.select('#' + this.elId)
.boundingClientRect(data => {
if (!data.height) {
setTimeout(() => {
this.queryRect();
}, 10);
return;
}
this.height = data.height;
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html
// 组件内部一般用this.$uGetRect,对外的为this.$u.getRect,二者功能一致,名称不同
this.$uGetRect('#' + this.elId).then(res => {
this.height = res.height;
})
.exec();
}
}
};
......@@ -163,17 +160,16 @@
justify-content: space-between;
align-items: center;
color: $u-main-color;
font-size: 30rpx;
line-height: 1;
padding: 24rpx 0;
text-align: left;
}
.u-collapse-title {
flex: 1;
overflow: hidden;
margin-right: 14rpx;
font-size: 30rpx;
color: $u-main-color;
line-height: 1;
padding: 24rpx 0;
text-align: left;
}
.u-arrow-down-icon {
......
......@@ -40,6 +40,13 @@
return {}
}
},
// 每一个item的样式
itemStyle: {
type: Object,
default () {
return {}
}
},
// 是否显示右侧的箭头
arrow: {
type: Boolean,
......
......@@ -232,12 +232,13 @@ export default {
if(this.showDays) {
showHour = hour;
} else {
// 如果不显示天数,将“天”部分的时间折算到小时中去
showHour = Math.floor(seconds / (60 * 60));
}
minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60;
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
// 如果小于10,在前面补上一个"0"
hour = hour < 10 ? '0' + hour : hour;
showHour = showHour < 10 ? '0' + showHour : showHour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
this.d = day;
......
......@@ -6,30 +6,35 @@
<view class="u-form-item--left" :style="{
width: labelPosition == 'left' ? labelWidth + 'rpx' : '100%',
flex: `0 0 ${labelPosition == 'left' ? labelWidth + 'rpx' : '100%'}`,
marginBottom: labelPosition == 'left' ? 0 : '10rpx'
marginBottom: labelPosition == 'left' ? 0 : '10rpx',
}">
<!-- 为了块对齐 -->
<view class="u-form-item--left__content">
<!-- nvue不支持伪元素before -->
<text v-if="isRequired" class="u-form-item--left__content--required">*</text>
<view class="u-form-item--left__content__icon" v-if="leftIcon">
<u-icon :name="leftIcon"></u-icon>
<u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
</view>
<view class="u-form-item--left__content__label" :style="[labelStyle]">
<view class="u-form-item--left__content__label" :style="[labelStyle, {
'justify-content': labelAlign == 'left' ? 'flex-star' : labelAlign == 'center' ? 'center' : 'flex-end'
}]">
{{label}}
</view>
</view>
</view>
<view class="u-form-item--right">
<view class="u-form-item--right u-flex">
<view class="u-form-item--right__content">
<view class="u-form-item--right__content__slot">
<view class="u-form-item--right__content__slot ">
<slot />
</view>
<u-icon v-if="rightIcon" :name="rightIcon"></u-icon>
<view class="u-form-item--right__content__icon u-flex" v-if="$slots.right || rightIcon">
<u-icon :custom-style="rightIconStyle" v-if="rightIcon" :name="rightIcon"></u-icon>
<slot name="right" />
</view>
</view>
</view>
</view>
<view class="u-form-item__message" v-if="validateState === 'error' && showError('message')" :style="{
paddingLeft: labelPosition == 'left' ? `${labelWidth}rpx` : '0',
}">{{validateMessage}}</view>
......@@ -44,7 +49,13 @@ schema.warning = function(){};
export default {
name: 'u-form-item',
mixins: [Emitter],
inject: ['uForm'],
inject: {
uForm: {
default() {
return null
}
}
},
props: {
// input的label提示语
label: {
......@@ -56,10 +67,10 @@ export default {
type: String,
default: ''
},
// 输入框的边框,bottom-显示下边框,surround-四周边框
// 是否显示表单域的下划线边框
borderBottom: {
type: String,
default: 'bottom'
type: Boolean,
default: true
},
// label的位置,left-左边,top-上边
labelPosition: {
......@@ -78,6 +89,11 @@ export default {
return {}
}
},
// lable字体的对齐方式
labelAlign: {
type: String,
default: 'left'
},
// 右侧图标
rightIcon: {
type: String,
......@@ -88,12 +104,18 @@ export default {
type: String,
default: ''
},
// 有错误时的提示方式,message-提示信息,border-下边框呈现红色,
// all-所有提示方式同时起效,toast-只对提交表单时有效,none-无提示
errorType: {
type: Array,
// 左侧图标的样式
leftIconStyle: {
type: Object,
default() {
return {}
}
},
// 左侧图标的样式
rightIconStyle: {
type: Object,
default() {
return ['message', 'border', 'border-bottom']
return {}
}
}
},
......@@ -102,16 +124,20 @@ export default {
initialValue: '', // 存储的默认值
isRequired: false, // 是否必填
validateState: '', // 是否校验成功
validateMessage: '' // 校验失败的提示语
validateMessage: '' ,// 校验失败的提示语
// 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色,
// border-bottom-下边框呈现红色,none-无提示
errorType: ['message']
};
},
watch: {
validateState(val) {
// 箱子组件发出事件,第三个参数为true或者false,true代表有错误
if(this.showError('border')) {
this.broadcast('u-input', 'on-form-item-error', val === 'error');
}
this.broadcastInputError();
},
// 监听u-form组件的errorType的变化
"uForm.errorType"(val) {
this.errorType = val;
this.broadcastInputError();
}
},
computed: {
......@@ -125,10 +151,13 @@ export default {
else if(this.errorType.indexOf(type) >= 0) return true;
else return false;
}
},
}
},
methods: {
broadcastInputError() {
// 子组件发出事件,第三个参数为true或者false,true代表有错误
this.broadcast('u-input', 'on-form-item-error', this.validateState === 'error' && this.showError('border'));
},
// 判断是否需要required校验
setRules() {
let that = this;
......@@ -199,15 +228,18 @@ export default {
// 清空当前的u-form-item
resetField() {
this.uForm.model[this.prop] = this.initialValue;
// 设置为`success`状态,只是为了清空错误标记
this.validateState = 'success';
}
},
// 组件创建完成时,将当前实例保存到u-form中
mounted() {
// 如果没有传入prop,就不进行校验
if (!this.prop) return;
// 如果没有传入prop,或者uForm为空(如果u-form-input单独使用,就不会有uForm注入),就不进行校验
if (!this.prop || this.uForm === null) return;
// 发出事件,让父组件将本实例加入到管理数组中
this.dispatch('u-form', 'on-form-item-add', this);
this.errorType = this.uForm.errorType;
// 设置初始值
this.initialValue = this.fieldValue;
// 添加表单校验
......@@ -229,7 +261,7 @@ export default {
font-size: 28rpx;
color: $u-main-color;
box-sizing: border-box;
// line-height: $u-form-item-height;
line-height: $u-form-item-height;
flex-direction: column;
&__border-bottom--error:after {
......@@ -249,9 +281,10 @@ export default {
display: flex;
align-items: center;
padding-right: 10rpx;
flex: 1;
&__icon {
margin-right: 4rpx;
margin-right: 8rpx;
}
&--required {
......@@ -265,6 +298,7 @@ export default {
&__label {
display: flex;
align-items: center;
flex: 1;
}
}
}
......@@ -275,9 +309,18 @@ export default {
&__content {
display: flex;
align-items: center;
flex: 1;
&__slot {
flex: 1;
/* #ifndef MP */
display: flex;
align-items: center;
/* #endif */
}
&__icon {
margin-left: 10rpx;
}
}
}
......
......@@ -19,7 +19,15 @@ export default {
// default() {
// return {};
// }
// }
// },
// 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色,
// border-bottom-下边框呈现红色,none-无提示
errorType: {
type: Array,
default() {
return ['message']
}
}
},
provide() {
return {
......
<template>
<view class="u-icon" @tap.stop.prevent="click" :class="[labelPos == 'bottom' ? 'u-flex-col u-row-center' : 'u-flex u-col-center']">
<view :style="[customStyle]" class="u-icon" @tap="click" :class="[labelPos == 'bottom' ? 'u-flex-col u-row-center' : 'u-flex u-col-center']">
<image class="u-icon__img" v-if="isImg" :src="name" :mode="imgMode" :style="[imgStyle]"></image>
<text v-else class="u-icon__icon" :class="customClass" :style="[iconStyle]" :hover-class="hoverClass" @touchstart="touchstart"></text>
<text v-if="label" class="u-icon__label" :style="{
......@@ -103,6 +103,13 @@ export default {
imgMode: {
type: String,
default: 'widthFix'
},
// 自定义样式
customStyle: {
type: Object,
default() {
return {}
}
}
},
data() {
......@@ -115,7 +122,9 @@ export default {
// uView的自定义图标类名为u-iconfont
if (this.customPrefix == 'uicon') classes.push('u-iconfont');
else classes.push(this.customPrefix);
//#ifdef MP-ALIPAY
// 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
// 故需将其拆成一个字符串的形式,通过空格隔开各个类名
//#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
classes = classes.join(' ');
//#endif
return classes;
......
......@@ -6,7 +6,9 @@
'u-input--error': validateState
}"
:style="{
padding: `0 ${border ? 20 : 0}rpx`
padding: `0 ${border ? 20 : 0}rpx`,
borderColor: borderColor,
textAlign: inputAlign
}"
@tap.stop="inputClick"
>
......@@ -19,6 +21,7 @@
:placeholderStyle="placeholderStyle"
:disabled="disabled"
:maxlength="inputMaxlength"
:fixed="fixed"
:focus="focus"
:autoHeight="autoHeight"
@input="handleInput"
......@@ -29,10 +32,10 @@
<input
v-else
class="u-input__input"
:type="type == 'password' ? 'text' : type"
:style="[getStyle]"
:type="type"
:value="defaultValue"
:password="(type == 'password' || password) && showPassword"
:password="type == 'password' && showPassword"
:placeholder="placeholder"
:placeholderStyle="placeholderStyle"
:disabled="disabled || type === 'select'"
......@@ -48,10 +51,10 @@
<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="clearable && value && focused">
<u-icon size="32" name="close-circle-fill" color="#c0c4cc" @touchstart="onClear"/>
</view>
<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="type == 'password' || password">
<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="passwordIcon && type == 'password'">
<u-icon size="32" :name="showPassword ? 'eye' : 'eye-fill'" color="#c0c4cc" @click="showPassword = !showPassword"/>
</view>
<view class="u-input__right-icon--select u-input__right-icon__item" v-if="type=='select'" :class="{
<view class="u-input__right-icon--select u-input__right-icon__item" v-if="type == 'select'" :class="{
'u-input__right-icon--select--reverse': selectOpen
}">
<u-icon name="arrow-down-fill" size="26" color="#c0c4cc"></u-icon>
......@@ -85,7 +88,7 @@ export default {
},
placeholder: {
type: String,
default: ''
default: '请输入内容'
},
disabled: {
type: Boolean,
......@@ -110,20 +113,30 @@ export default {
return {};
}
},
// 如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true
fixed: {
type: Boolean,
default: false
},
// 是否自动获得焦点
focus: {
type: Boolean,
default: false
},
// 是否密码类型
password: {
// 密码类型时,是否显示右侧的密码图标
passwordIcon: {
type: Boolean,
default: false
default: true
},
// input|textarea是否显示边框
border: {
type: Boolean,
default: true
default: false
},
// 输入框的边框颜色
borderColor: {
type: String,
default: '#dcdfe6'
},
autoHeight: {
type: Boolean,
......@@ -153,7 +166,8 @@ export default {
textareaHeight: 100, // textarea的高度
validateState: false, // 当前input的验证状态,用于错误时,边框是否改为红色
focused: false, // 当前是否处于获得焦点的状态
showPassword: this.password, // 是否预览密码
showPassword: this.passwordIcon, // 是否预览密码
marginRight: 0, // 输入框右边的距离,当获得焦点时各一个后面的距离,避免点击右边图标误触输入框
};
},
watch: {
......@@ -166,6 +180,11 @@ export default {
}
})
},
focused(nVal) {
if(this.clearable && this.value) {
this.getMarginRight();
}
}
},
computed: {
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
......@@ -177,14 +196,28 @@ export default {
// 如果没有自定义高度,就根据type为input还是textare来分配一个默认的高度
style.minHeight = this.height ? this.height + 'rpx' : this.type == 'textarea' ?
this.textareaHeight + 'rpx' : this.inputHeight + 'rpx';
style.marginRight = this.marginRight + 'px';
style = Object.assign(style, this.customStyle);
return style;
}
},
created() {
// 监听u-form-item发出的错误事件,将输入框边框变红色
this.$on('on-form-item-error', this.onFormItemError);
},
mounted() {
this.getMarginRight();
},
methods: {
// 计算输入框的右边距
getMarginRight() {
this.$nextTick(() => {
this.$uGetRect('.u-input__right-icon').then(res => {
// 此处20rpx为图标绝对定位右侧的“right”
this.marginRight = res.width + uni.upx2px(20);
})
})
},
/**
* change 事件
* @param event
......@@ -237,6 +270,7 @@ export default {
<style lang="scss" scoped>
.u-input {
position: relative;
flex: 1;
&__input {
//height: $u-form-item-height;
......@@ -259,14 +293,14 @@ export default {
}
&--error {
border-color: $u-type-error;
border-color: $u-type-error!important;
}
&__right-icon {
position: absolute;
right: 20rpx;
top: 50%;
z-index: 1;
z-index: 3;
transform: translateY(-50%);
&__item {
......
......@@ -129,7 +129,6 @@
},
// 键盘关闭
popupClose() {
console.log(333);
// 通过发送input这个特殊的事件名,可以修改父组件传给props的value的变量,也即双向绑定
this.$emit('input', false);
},
......
......@@ -5,7 +5,7 @@
<view class="u-navbar-inner" :style="[navbarInnerStyle]">
<view class="u-back-wrap" v-if="isBack" @tap="goBack">
<view class="u-icon-wrap">
<u-icon :name="backIconName" :color="backIconColor" :size="backIconSize"></u-icon>
<u-icon @click="goBack" :name="backIconName" :color="backIconColor" :size="backIconSize"></u-icon>
</view>
<view class="u-icon-wrap u-back-text u-line-1" v-if="backText" :style="[backTextStyle]">
{{backText}}
......
<template>
<view class="u-radio" :style="[radioStyle]">
<view class="u-radio__icon-wrap" @tap="toggle">
<u-icon @tap="toggle" :class="iconClass" name="checkbox-mark" :size="iconSize" :color="iconColor" class="u-radio__icon" :style="[iconStyle]" />
<u-icon :class="iconClass" name="checkbox-mark" :size="iconSize" :color="iconColor" class="u-radio__icon" :style="[iconStyle]" />
</view>
<view class="u-label-class u-radio__label" @tap="onClickLabel" :style="{
fontSize: labelSize + 'rpx'
......
......@@ -9,7 +9,7 @@
:disabled="disabled"
:x="moveX"
:style="{
width: movableViewWidth
width: movableViewWidth ? movableViewWidth : '100%'
}"
>
<view
......@@ -18,7 +18,7 @@
>
<slot></slot>
</view>
<view class="u-swipe-del" @tap.stop="btnClick(index)" :style="[btnStyle(item.style)]" v-for="(item, index) in options" :key="index">
<view class="u-swipe-del" v-if="showBtn" @tap.stop="btnClick(index)" :style="[btnStyle(item.style)]" v-for="(item, index) in options" :key="index">
<view class="u-btn-text">{{ item.text }}</view>
</view>
</movable-view>
......@@ -101,7 +101,8 @@ export default {
scrollX: 0, // movable-view移动过程中产生的change事件中的x轴移动值
status: false, // 滑动的状态,表示当前是展开还是关闭按钮的状态
movableAreaWidth: 0, // 滑动区域
elId: this.$u.guid() // id,用于通知另外组件关闭时的识别
elId: this.$u.guid(), // id,用于通知另外组件关闭时的识别
showBtn: false, // 刚开始渲染视图时不显示右边的按钮,避免视图闪动
};
},
computed: {
......@@ -124,6 +125,10 @@ export default {
},
mounted() {
this.getActionRect();
// 等视图更新完后,再显示右边的可滑动按钮,防止这些按钮会"闪一下"
this.$nextTick(() => {
this.showBtn = true;
})
},
methods: {
// 点击按钮
......
......@@ -21,7 +21,7 @@
width: width + 'rpx',
height: width + 'rpx'
}">
<u-icon name="plus" class="u-add-btn" size="40"></u-icon>
<u-icon name="plus" class="u-add-btn" size="40" @click="selectFile"></u-icon>
<view class="u-add-tips">{{uploadText}}</view>
</view>
</view>
......
......@@ -41,6 +41,10 @@ import color from './libs/function/color.js'
import type2icon from './libs/function/type2icon.js'
// 打乱数组的顺序
import randomArray from './libs/function/randomArray.js'
// 对象和数组的深度克隆
import deepClone from './libs/function/deepClone.js'
// 对象深度拷贝
import deepMerge from './libs/function/deepMerge.js'
// 规则检验
import test from './libs/function/test.js'
......@@ -50,8 +54,7 @@ import random from './libs/function/random.js'
import trim from './libs/function/trim.js'
// toast提示,对uni.showToast的封装
import toast from './libs/function/toast.js'
// 对象和数组的深度克隆
import deepClone from './libs/function/deepClone.js'
// 配置信息
import config from './libs/config/config.js'
......@@ -79,6 +82,7 @@ const $u = {
test,
random,
deepClone,
deepMerge,
trim,
type: ['primary', 'success', 'error', 'warning', 'info'],
http,
......
function deepClone(obj){
var o,i,j,k;
if(typeof(obj)!=="object" || obj===null)return obj;
if(obj instanceof Array){
o=[];
i=0;j=obj.length;
for(;i<j;i++){
if(typeof(obj[i])==="object" && obj[i]!=null){
o[i]=deepClone(obj[i]);
}else{
o[i]=obj[i];
// 对象深度克隆
function deepClone(object = {}) {
var o, i, j, k;
if (typeof(object) !== "object" || object === null) return object;
if (object instanceof Array) {
o = [];
i = 0;
j = object.length;
for (; i < j; i++) {
if (typeof(object[i]) === "object" && object[i] != null) {
o[i] = deepClone(object[i]);
} else {
o[i] = object[i];
}
}
}else{
o={};
for(i in obj){
if(typeof(obj[i])==="object" && obj[i]!==null){
o[i]=deepClone(obj[i]);
}else{
o[i]=obj[i];
} else {
o = {};
for (i in object) {
if (typeof(object[i]) === "object" && object[i] !== null) {
o[i] = deepClone(object[i]);
} else {
o[i] = object[i];
}
}
}
......
import deepClone from "./deepClone";
// JS对象深度合并
function deepMerge(target = {}, source = {}) {
target = deepClone(target);
if (typeof target !== 'object' || typeof source !== 'object') return false;
for (var prop in source) {
if (!source.hasOwnProperty(prop)) continue;
if (prop in target) {
if (typeof target[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (typeof source[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop]);
} else {
target[prop] = deepMerge(target[prop], source[prop]);
}
}
}
} else {
target[prop] = source[prop];
}
}
return target;
}
export default deepMerge;
\ No newline at end of file
......@@ -15,7 +15,6 @@ function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
timer = parseInt(timer / 1000);
// 如果小于5分钟,则返回"刚刚",其他以此类推
let tips = '';
console.log(timer);
switch (true) {
case timer < 300:
tips = '刚刚';
......
import deepMerge from "../function/deepMerge";
import validate from "../function/test";
class Request {
// 判断是否http|https开头的URL
static isHttp(url) {
return /(http|https):\/\/([\w.]+\/?)\S*/.test(url)
}
// 设置全局默认配置
setConfig(customConfig) {
this.config = Object.assign(this.config, customConfig);
// 深度合并对象,否则会造成对象深层属性丢失
this.config = deepMerge(this.config, customConfig);
}
// 主要请求部分
......@@ -57,7 +55,7 @@ class Request {
if (resInterceptors !== false) {
resolve(resInterceptors);
} else {
reject(response);
reject(resInterceptors);
}
} else {
// 如果不是返回原始数据(originalData=false),且没有拦截器的情况下,返回纯数据给then回调
......@@ -75,8 +73,8 @@ class Request {
}
}
// 判断用户传递的URL是否/开头,如果不是,加上/
options.url = Request.isHttp(options.url) ? options.url : (this.config.baseUrl + (options.url.indexOf('/') == 0 ?
// 判断用户传递的URL是否/开头,如果不是,加上/,这里使用了uView的test.js验证库的url()方法
options.url = validate.url(options.url) ? options.url : (this.config.baseUrl + (options.url.indexOf('/') == 0 ?
options.url : '/' + options.url));
// 是否显示loading
......@@ -92,7 +90,7 @@ class Request {
}, this.config.loadingTime);
}
uni.request(options);
}).catch(e => {})
})
}
constructor() {
......@@ -100,7 +98,8 @@ class Request {
baseUrl: '', // 请求的根域名
// 默认的请求头
header: {
'content-type': 'application/json;charset=UTF-8'
'content-type': 'application/json;charset=UTF-8',
'version': 1
},
method: 'POST',
// 设置为json,返回后uni.request会对数据进行一次JSON.parse
......
/**
* 表单验证
*
* @param {Object} rules 验证字段的规则
* @param {Object} messages 验证字段的提示信息
*/
class Uvalidattion {
constructor(rules = {}, messages = {}) {
Object.assign(this, {
data: {},
rules,
messages,
})
this.__init()
}
/**
* __init
*/
__init() {
this.__initMethods()
this.__initDefaults()
this.__initData()
}
/**
* 初始化数据
*/
__initData() {
this.form = {}
this.errorList = []
}
/**
* 初始化默认提示信息
*/
__initDefaults() {
this.defaults = {
messages: {
required: '请填写完整信息',
email: '请输入有效的邮箱',
tel: '请输入11位的手机号码',
url: '请输入有效的网址',
date: '请输入有效的日期',
dateISO: '请输入有效的日期(ISO)',
number: '请输入有效的数字',
digits: '只能输入数字',
idCard: '请输入18位的有效身份证',
equalTo: this.formatTpl('输入值必须和 {0} 相同。'),
contains: this.formatTpl('输入值必须包含 {0}。'),
minLength: this.formatTpl('最少要输入 {0} 个字符。'),
maxLength: this.formatTpl('最多可以输入 {0} 个字符。'),
rangeLength: this.formatTpl('请输入长度在 {0} 到 {1} 之间的字符。'),
min: this.formatTpl('请输入不小于 {0} 的数值。'),
max: this.formatTpl('请输入不大于 {0} 的数值。'),
range: this.formatTpl('请输入范围在 {0} 到 {1} 之间的数值。'),
carNo: '请输入有效的车牌号',
amount: '请输入有效的金额数值',
chinese: '只能输入汉字',
letter: '只能输入字母',
enOrNum: '只能包含字母和数字',
}
}
}
/**
* 初始化默认验证方法
*/
__initMethods() {
const that = this
that.methods = {
/**
* 验证必填元素
*/
required(value, param) {
if (!that.depend(param)) {
return 'dependency-mismatch'
} else if (typeof value === 'number') {
value = value.toString()
} else if (typeof value === 'boolean') {
return !0
}
return value.length > 0
},
/**
* 验证电子邮箱格式
*/
email(value) {
return that.optional(value) ||
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
.test(value)
},
/**
* 验证手机格式
*/
tel(value) {
return that.optional(value) || /^1[34578]\d{9}$/.test(value)
},
/**
* 验证URL格式
*/
url(value) {
return that.optional(value) ||
/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i
.test(value)
},
/**
* 验证日期格式
*/
date(value) {
return that.optional(value) || !/Invalid|NaN/.test(new Date(value).toString())
},
/**
* 验证ISO类型的日期格式
*/
dateISO(value) {
return that.optional(value) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
},
/**
* 验证十进制数字
*/
number(value) {
return that.optional(value) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
},
/**
* 验证整数
*/
digits(value) {
return that.optional(value) || /^\d+$/.test(value)
},
/**
* 验证身份证号码
*/
idCard(value) {
return that.optional(value) || /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value)
},
/**
* 是否车牌号
*/
carNo(value) {
// 新能源车牌
const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
// 旧车牌
const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
if (that.optional(value) || value.length === 7) {
return creg.test(value);
} else if (that.optional(value) || value.length === 8) {
return xreg.test(value);
} else {
return false;
}
},
/**
* 金额,只允许2位小数
*/
amount(value) {
//金额,只允许保留两位小数
return that.optional(value) || /^([0-9]*[.]?[0-9])[0-9]{0,1}$/.test(value);
},
/**
* 只能输入中文
*/
chinese(value) {
let reg = /^[\u4e00-\u9fa5]+$/gi;
return that.optional(value) || value !== "" && reg.test(value);
},
/**
* 只能输入字母
*/
letter(value) {
return that.optional(value) || /^[a-zA-Z]*$/.test(value);
},
/**
* 只能是字母或者数字
*/
enOrNum(value) {
//英文或者数字
let reg = /^[0-9a-zA-Z]*$/g;
return that.optional(value) || reg.test(value);
},
/**
* 验证两个输入框的内容是否相同
*/
equalTo(value, param) {
return that.optional(value) || value === that.data[param]
},
/**
* 验证是否包含某个值
*/
contains(value, param) {
return that.optional(value) || value.indexOf(param) >= 0
},
/**
* 验证最小长度
*/
minLength(value, param) {
return that.optional(value) || value.length >= param
},
/**
* 验证最大长度
*/
maxLength(value, param) {
return that.optional(value) || value.length <= param
},
/**
* 验证一个长度范围[min, max]
*/
rangeLength(value, param) {
return that.optional(value) || (value.length >= param[0] && value.length <= param[1])
},
/**
* 验证最小值
*/
min(value, param) {
return that.optional(value) || value >= param
},
/**
* 验证最大值
*/
max(value, param) {
return that.optional(value) || value <= param
},
/**
* 验证一个值范围[min, max]
*/
range(value, param) {
return that.optional(value) || (value >= param[0] && value <= param[1])
},
}
}
/**
* 添加自定义验证方法
* @param {String} name 方法名
* @param {Function} method 函数体,接收两个参数(value, param),value表示元素的值,param表示参数
* @param {String} message 提示信息
*/
addMethod(name, method, message) {
this.methods[name] = method
this.defaults.messages[name] = message !== undefined ? message : this.defaults.messages[name]
}
/**
* 判断验证方法是否存在
*/
isValidMethod(value) {
let methods = []
for (let method in this.methods) {
if (method && typeof this.methods[method] === 'function') {
methods.push(method)
}
}
return methods.indexOf(value) !== -1
}
/**
* 格式化提示信息模板
*/
formatTpl(source, params) {
const that = this
if (arguments.length === 1) {
return function() {
let args = Array.from(arguments)
args.unshift(source)
return that.formatTpl.apply(this, args)
}
}
if (params === undefined) {
return source
}
if (arguments.length > 2 && params.constructor !== Array) {
params = Array.from(arguments).slice(1)
}
if (params.constructor !== Array) {
params = [params]
}
params.forEach(function(n, i) {
source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function() {
return n
})
})
return source
}
/**
* 判断规则依赖是否存在
*/
depend(param) {
switch (typeof param) {
case 'boolean':
param = param
break
case 'string':
param = !!param.length
break
case 'function':
param = param()
default:
param = !0
}
return param
}
/**
* 判断输入值是否为空
*/
optional(value) {
return !this.methods.required(value) && 'dependency-mismatch'
}
/**
* 获取自定义字段的提示信息
* @param {String} param 字段名
* @param {Object} rule 规则
*/
customMessage(param, rule) {
const params = this.messages[param]
const isObject = typeof params === 'object'
if (params && isObject) return params[rule.method]
}
/**
* 获取某个指定字段的提示信息
* @param {String} param 字段名
* @param {Object} rule 规则
*/
defaultMessage(param, rule) {
let message = this.customMessage(param, rule) || this.defaults.messages[rule.method]
let type = typeof message
if (type === 'undefined') {
message = `Warning: No message defined for ${rule.method}.`
} else if (type === 'function') {
message = message.call(this, rule.parameters)
}
return message
}
/**
* 缓存错误信息
* @param {String} param 字段名
* @param {Object} rule 规则
* @param {String} value 元素的值
*/
formatTplAndAdd(param, rule, value) {
let msg = this.defaultMessage(param, rule)
this.errorList.push({
param: param,
msg: msg,
value: value,
})
}
/**
* 验证某个指定字段的规则
* @param {String} param 字段名
* @param {Object} rules 规则
* @param {Object} data 需要验证的数据对象
*/
checkParam(param, rules, data) {
// 缓存数据对象
this.data = data
// 缓存字段对应的值
const value = data[param] !== null && data[param] !== undefined ? data[param] : ''
// 遍历某个指定字段的所有规则,依次验证规则,否则缓存错误信息
for (let method in rules) {
// 判断验证方法是否存在
if (this.isValidMethod(method)) {
// 缓存规则的属性及值
const rule = {
method: method,
parameters: rules[method]
}
// 调用验证方法
const result = this.methods[method](value, rule.parameters)
// 若result返回值为dependency-mismatch,则说明该字段的值为空或非必填字段
if (result === 'dependency-mismatch') {
continue
}
this.setValue(param, method, result, value)
// 判断是否通过验证,否则缓存错误信息,跳出循环
if (!result) {
this.formatTplAndAdd(param, rule, value)
break
}
}
}
}
/**
* 设置字段的默认验证值
* @param {String} param 字段名
*/
setView(param) {
this.form[param] = {
$name: param,
$valid: true,
$invalid: false,
$error: {},
$success: {},
$viewValue: ``,
}
}
/**
* 设置字段的验证值
* @param {String} param 字段名
* @param {String} method 字段的方法
* @param {Boolean} result 是否通过验证
* @param {String} value 字段的值
*/
setValue(param, method, result, value) {
const params = this.form[param]
params.$valid = result
params.$invalid = !result
params.$error[method] = !result
params.$success[method] = result
params.$viewValue = value
}
/**
* 验证所有字段的规则,返回验证是否通过
* @param {Object} data 需要验证数据对象
*/
checkForm(data) {
this.__initData()
for (let param in this.rules) {
this.setView(param)
this.checkParam(param, this.rules[param], data)
}
return this.valid()
}
/**
* 返回验证是否通过
*/
valid() {
return this.size() === 0
}
/**
* 返回错误信息的个数
*/
size() {
return this.errorList.length
}
/**
* 返回所有错误信息
*/
validationErrors() {
return this.errorList
}
}
export default Uvalidattion;
{
"name": "uview-ui",
"version": "1.2.9",
"version": "1.3.0",
"description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水",
"main": "index.js",
"keywords": ["uview", "uView", "uni-app", "uni-app ui", "uniapp", "uviewui", "uview ui", "uviewUI", "uViewui", "uViewUI", "uView UI", "uni ui", "uni UI", "uniapp ui", "ui", "UI框架", "uniapp ui框架", "uniapp UI"],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment