Commit 9e15c6cf authored by wlxuqu's avatar wlxuqu

1. form表单验证新增toast的错误提示方式,配置erroryType=['toast']即可

2. search搜索框组件新增search-icon参数,可自定义左侧的图标
3. card组件新增可控制头部和尾部显示与否的show-head和show-foot参数
4. collapse组件新增控制头部的slot参数title和title-all
5. form-item组件左侧红色星标通过required参数配置,仅起展示作用,如需校验是否填写请配置rules规则
6. 改正section组件的show-line默认为false的问题
7. 修复popup组件在低性能安卓设备上可能存在弹出动画无效的问题
8. 修复line线条组件可能在小程序上无效的问题
9. 修复upload组件在H5上可能弹出两次选择文件窗口的问题
10. 修复verificationCode验证码倒计时设置保持倒计时模式时多次切换页面倒计时可能混乱的问题
11. 修复calendar日历组件的关闭按钮在支付宝小程序上位置不对的问题
12. 修复numberBox组件渲染完成时自动触发一次change事件的问题
parent 3765301b
...@@ -19,6 +19,15 @@ uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全 ...@@ -19,6 +19,15 @@ uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全
- 按需引入,精简打包体积 - 按需引入,精简打包体积
## 友情链接
<br>
#### **vue-admin-beautiful** —— [企业级、通用型中后台前端解决方案(基于vue/cli 4 最新版,同时支持电脑,手机,平板)](https://github.com/chuzhixin/vue-admin-beautiful)
#### **vue-admin-beautiful** —— [在线演示](http://beautiful.panm.cn/vue-admin-beautiful/#/index)
<br>
## 安装 ## 安装
```bash ```bash
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
"versionCode" : "100", "versionCode" : "100",
"transformPx" : false, "transformPx" : false,
"app-plus" : { "app-plus" : {
// APP-VUE分包,可提APP升启动速度,2.7.12开始支持,兼容微信小程序分包方案,默认关闭
"optimization" : {
"subPackages" : true
},
"safearea" : { "safearea" : {
"bottom" : { "bottom" : {
"offset" : "none" "offset" : "none"
......
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
"easycom": { "easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
}, },
"condition": { //模式配置,仅开发期间生效 // "condition": { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项) // "current": 0, //当前激活的模式(list 的索引项)
"list": [{ // "list": [{
"name": "test", //模式名称 // "name": "test", //模式名称
"path": "pages/template/citySelect/index", //启动页面,必选 // "path": "pages/componentsB/swipeAction/index", //启动页面,必选
"query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到 // "query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到
}] // }]
}, // },
"pages": [ "pages": [
// 演示-组件 // 演示-组件
{ {
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
<view class="u-demo-wrap"> <view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view> <view class="u-demo-title">演示效果</view>
<view class="u-demo-area"> <view class="u-demo-area">
<view class="u-no-demo-here">
滚动页面,在由下角即可看到返回顶部按钮
</view>
<u-empty :mode="mode"> <u-empty :mode="mode">
<u-button v-if="slot" slot="bottom" size="medium"> <u-button v-if="slot" slot="bottom" size="medium">
slot按钮 slot按钮
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
</view> </view>
<view class="u-config-item"> <view class="u-config-item">
<view class="u-item-title">错误提示方式</view> <view class="u-item-title">错误提示方式</view>
<u-subsection vibrateShort :list="['文字', '下划线', '输入框', '下划线+文字']" @change="errorChange"></u-subsection> <u-subsection vibrateShort :list="['message', 'toast', '下划线', '输入框']" @change="errorChange"></u-subsection>
</view> </view>
</view> </view>
</view> </view>
...@@ -131,6 +131,7 @@ export default { ...@@ -131,6 +131,7 @@ export default {
trigger: ['change','blur'], trigger: ['change','blur'],
}, },
{ {
// 此为同步验证,可以直接返回true或者false,如果是异步验证,稍微不同,见下方说明
validator: (rule, value, callback) => { validator: (rule, value, callback) => {
// 调用uView自带的js验证规则,详见:https://www.uviewui.com/js/test.html // 调用uView自带的js验证规则,详见:https://www.uviewui.com/js/test.html
return this.$u.test.chinese(value); return this.$u.test.chinese(value);
...@@ -138,7 +139,24 @@ export default { ...@@ -138,7 +139,24 @@ export default {
message: '姓名必须为中文', message: '姓名必须为中文',
// 触发器可以同时用blur和change,二者之间用英文逗号隔开 // 触发器可以同时用blur和change,二者之间用英文逗号隔开
trigger: ['change','blur'], trigger: ['change','blur'],
} },
// 异步验证,用途:比如用户注册时输入完账号,后端检查账号是否已存在
// {
// trigger: ['blur'],
// // 异步验证需要通过调用callback(),并且在里面抛出new Error()
// // 抛出的内容为需要提示的信息,和其他方式的message属性的提示一样
// asyncValidator: (rule, value, callback) => {
// this.$u.post('/ebapi/public_api/index').then(res => {
// // 如果验证出错,需要在callback()抛出new Error('错误提示信息')
// if(res.error) {
// callback(new Error('姓名重复'));
// } else {
// // 如果没有错误,也要执行callback()回调
// callback();
// }
// })
// },
// }
], ],
sex: [ sex: [
{ {
...@@ -410,12 +428,9 @@ export default { ...@@ -410,12 +428,9 @@ export default {
}, },
errorChange(index) { errorChange(index) {
if(index == 0) this.errorType = ['message']; if(index == 0) this.errorType = ['message'];
if(index == 1) this.errorType = ['border-bottom']; if(index == 1) this.errorType = ['toast'];
if(index == 2) { if(index == 2) this.errorType = ['border-bottom'];
this.errorType = ['border']; if(index == 3) this.errorType = ['border'];
this.border = true;
}
if(index == 3) this.errorType = ['message', 'border-bottom'];
} }
} }
}; };
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<view class="u-demo-title">演示效果</view> <view class="u-demo-title">演示效果</view>
<view class="u-demo-area"> <view class="u-demo-area">
<u-toast ref="uToast"></u-toast> <u-toast ref="uToast"></u-toast>
<u-verification-code :seconds="seconds" @end="end" @start="start" ref="uCode" <u-verification-code :keep-running="true" :seconds="seconds" @end="end" @start="start" ref="uCode"
@change="codeChange" :startText="startText" :changeText="changeText" @change="codeChange" :startText="startText" :changeText="changeText"
:endText="endText"></u-verification-code> :endText="endText"></u-verification-code>
<u-button @click="getCode">{{tips}}</u-button> <u-button @click="getCode">{{tips}}</u-button>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<view class=""> <view class="">
<view class="u-card-wrap"> <view class="u-card-wrap">
<u-card @click="click" @head-click="headClick" :title="title" :sub-title="subTitle" :thumb="thumb" :padding="padding" :border="border"> <u-card @click="click" @head-click="headClick" :title="title" :sub-title="subTitle" :thumb="thumb" :padding="padding" :border="border">
<view class="" slot="body"> <view class="" slot="body">
<view class="u-body-item u-flex u-border-bottom u-col-between u-p-t-0"> <view class="u-body-item u-flex u-border-bottom u-col-between u-p-t-0">
<view class="u-body-item-title u-line-2"> <view class="u-body-item-title u-line-2">
瓶身描绘的牡丹一如你初妆,冉冉檀香透过窗心事我了然,宣纸上走笔至此搁一半 瓶身描绘的牡丹一如你初妆,冉冉檀香透过窗心事我了然,宣纸上走笔至此搁一半
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
list: [ list: [
{ {
name: '荔枝', name: '荔枝',
checked: false, checked: true,
disabled: false disabled: false
}, },
{ {
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
disabled: false, disabled: false,
result: '', result: '',
shape: 'square', shape: 'square',
value: '', value: '荔枝',
activeColor: '#2979ff', activeColor: '#2979ff',
size: 34, size: 34,
wrap: false, wrap: false,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<view class="u-demo-area"> <view class="u-demo-area">
<u-toast ref="uToast"></u-toast> <u-toast ref="uToast"></u-toast>
<u-search v-model="value" @change="change" @custom="custom" @search="search" :shape="shape" :clearabled="clearabled" <u-search v-model="value" @change="change" @custom="custom" @search="search" :shape="shape" :clearabled="clearabled"
:show-action="showAction" :input-align="inputAlign"></u-search> :show-action="showAction" :input-align="inputAlign" @clear="clear"></u-search>
</view> </view>
</view> </view>
<view class="u-config-wrap"> <view class="u-config-wrap">
...@@ -83,6 +83,9 @@ ...@@ -83,6 +83,9 @@
title: '搜索内容为:' + value, title: '搜索内容为:' + value,
type: 'success' type: 'success'
}) })
},
clear() {
// console.log(this.value);
} }
} }
} }
......
...@@ -89,7 +89,7 @@ export default { ...@@ -89,7 +89,7 @@ export default {
onLoad() { onLoad() {
setTimeout(() => { setTimeout(() => {
this.list = this.list1; this.list = this.list1;
}, 2000) }, 0)
}, },
methods: { methods: {
disabledChange(index) { disabledChange(index) {
......
...@@ -63,7 +63,7 @@ export default { ...@@ -63,7 +63,7 @@ export default {
this.step = index == 0 ? 1 : index == 1 ? 3 : index == 2 ? 5 : 8; this.step = index == 0 ? 1 : index == 1 ? 3 : index == 2 ? 5 : 8;
}, },
change(e) { change(e) {
// console.log(this.value); console.log(this.value);
} }
} }
}; };
......
...@@ -83,9 +83,7 @@ ...@@ -83,9 +83,7 @@
// console.log('open'); // console.log('open');
}, },
btnClick() { btnClick() {
console.log(this.show);
this.show = true; this.show = true;
console.log(this.show);
} }
} }
} }
......
<template> <template>
<view class="wrap"> <view>
<text>滑动页面,返回顶部按钮将出现在右下角</text> <!-- {{hasLogin}}||{{provider}}||{{openid}} -->
<u-back-top :scrollTop="scrollTop" :mode="mode" :icon-style="iconStyle"></u-back-top> <image src="http://www.gyb086.com/Content/Home/images/regist-logo_03.jpg" mode="aspectFill" class="logo"></image>
<view class="loginWarp">
<view class="u-border-bottom">
<u-cell-group :border="false">
<u-field :field-style="fieldStyle" v-model="formData.name" placeholder="请输入用户名" label-width="20" :placeholder-style="placeholderClass">
<text class="iconfont icon-xingmingyonghumingnicheng color_gray2 u-padding-top-30" slot="icon"></text>
</u-field>
<u-field :field-style="fieldStyle" :password="true" v-model="formData.password" placeholder="请输入密码" label-width="20" :placeholder-style="placeholderClass">
<text class="iconfont icon-mima color_gray2 u-padding-top-30" slot="icon"></text>
<text class="iconfont icon-yanjing color_gray2" slot="right"></text>
</u-field>
<u-field :field-style="fieldStyle" v-model="formData.phone" placeholder="请输入手机号" label-width="20" :placeholder-style="placeholderClass">
<text class="iconfont icon-shoujihao color_gray2 u-padding-top-30" slot="icon"></text>
</u-field>
<u-field :field-style="fieldStyle" v-model="formData.code" placeholder="请填写验证码" label-width="20" :placeholder-style="placeholderClass">
<text class="iconfont icon-_yanzhengma color_gray2 u-padding-top-30" slot="icon"></text>
<!-- <u-button size="mini" slot="right" type="success" @tap="getCode">获取验证码</u-button> -->
<!-- <u-toast ref="uToast"></u-toast> -->
<text class="color_green u-padding-top-30" slot="right" @click="getCode">{{ tips }}</text>
</u-field>
</u-cell-group>
</view>
<view class="loginbtn">
<u-button :custom-style="btnColor" type="success" shape="circle" :ripple="true" ripple-bg-color="#19be6b" @click="login()">
登录
</u-button>
</view>
<navigator url="/pages/register/register" class="color_gray8 f28 text_ac">快速注册</navigator>
<!-- <navigator class="wxLogin"><text class="iconfont icon-weixin1"></text></navigator> -->
<u-button class="wxbtn" type="success" :custom-style="wxLogin" shape="circle" :plain="true" :hair-line="false" open-type="getPhoneNumber" @getphonenumber="getphonenumber">
<text class="iconfont icon-weixin1 wxicon"></text>
</u-button>
<u-verification-code seconds="60" :keep-running="true" @end="end" @start="start" ref="uCode" @change="codeChange"></u-verification-code>
</view>
</view> </view>
</template> </template>
<script> <script>
import { mapState, mapMutations } from 'vuex';
export default { export default {
data() { data() {
return { return {
scrollTop: 0, placeholderClass: 'color:#c4c4c5;',
mode: 'square', fieldStyle: {
iconStyle: { paddingTop: '30rpx',
fontSize: '32rpx', },
color: '#2979ff' wxLogin:{
border:'none',
borderColor:'#fff',
backgroundColor:'none',
height: '120rpx',
width:'120rpx',
color: '#fff',
fontSize: '70rpx',
marginTop:'120px'
},
btnColor:{
backgroundColor: '#338b39',
borderColor: '#338b39'
},
formData: {
name: '高供货',
password: '123456',
phone: '13730508115',
code: '888',
verCode: '',
wxPhone: '',
codeSession_key: ''
},
tips: '获取验证码'
};
},
// computed: {
// ...mapState(['hasLogin', 'provider', 'openid', 'session_key'])
// },
methods: {
//...mapMutations(['setOpenid', 'loginSetData']),
// 获取微信用户手机号 快捷登陆
getphonenumber: function(e) {
// console.log(e);
let getWxPhone = this.util.getWxPhone(e.detail.encryptedData, this.session_key, e.detail.iv);
this.formData.wxPhone = getWxPhone.phoneNumber;
console.log(this.formData.wxPhone);
this.request
.post('/Common/Login/', {
ciphertext: {
nvc_platform: '1',
nvc_wx_identifier: this.openid,
nvc_phone: this.formData.wxPhone
}
})
.then(res => {
console.log(res);
if(res.code == 400){
this.$u.toast('您还未绑定平台账号,请先登陆后进行绑定');
}
// uni.hideLoading();
// // 这里此提示会被this.start()方法中的提示覆盖
// this.$u.toast('验证码已发送');
// // 通知验证码组件内部开始倒计时
// this.$refs.uCode.start();
})
.catch(e => {
});
},
// 获取验证码
codeChange(text) {
this.tips = text;
},
getCode() {
console.log(this.$refs.uCode);
if (this.$refs.uCode.canGetCode) {
if (this.$u.test.isEmpty(this.formData.name)) {
this.$u.toast('请输入用户名');
return;
} else if (this.$u.test.isEmpty(this.formData.phone)) {
this.$u.toast('请输入手机号');
return;
} else {
uni.showLoading({
title: '正在获取验证码'
});
this.request
.post('/Common/SendMobileCode/', {
ciphertext: {
nvc_platform: '1',
sendType: '1',
number: this.formData.phone,
userName: this.formData.name
}
})
.then(res => {
console.log(res);
if(res.success == true){
uni.hideLoading();
// 这里此提示会被this.start()方法中的提示覆盖
this.$u.toast('验证码已发送');
this.formData.codeSession_key = res.data.session_key
// 通知验证码组件内部开始倒计时
this.$refs.uCode.start();
}else{
this.$u.toast(res.msg);
}
})
.catch(e => {});
}
} else {
this.$u.toast('倒计时结束后再发送');
}
},
end() {
// this.$u.toast('倒计时结束');
},
start() {
this.$u.toast('验证码已发送啊啊');
},
login(){
if (this.$u.test.isEmpty(this.formData.name)) {
this.$u.toast('请输入用户名');
return;
} else if (this.$u.test.isEmpty(this.formData.password)) {
this.$u.toast('请输入密码');
return;
} else if (this.$u.test.isEmpty(this.formData.phone)) {
this.$u.toast('请输入手机号');
return;
} else if(!this.$u.test.mobile(this.formData.phone)){
this.$u.toast('请输入正确的手机号');
return;
}else if(this.$u.test.isEmpty(this.formData.code)){
this.$u.toast('请输入验证码');
return;
}else{
this.request
.post('/Common/Login/', {
ciphertext: {
nvc_platform: '1',
nvc_user_name: this.formData.name,
nvc_pass_word: this.formData.password,
nvc_phone:this.formData.phone,
mobile_code:this.formData.code,
session_key:this.formData.codeSession_key
}
})
.then(res => {
console.log(res);
// debugger
if(res.success == true){
this.loginSetData({
loginUser:res.data.loginUser,
loginPersonInfo:res.data.loginPersonInfo
})
uni.setStorageSync('userData',{
loginUser:res.data.loginUser,
loginPersonInfo:res.data.loginPersonInfo
})
uni.switchTab({
url:'../me/me-index/me-index'
})
this.$u.toast('登录成功');
}
})
.catch(e => {});
} }
} }
}, },
onPageScroll(e) { onLoad: function() {
this.scrollTop = e.scrollTop; // console.log(this.openid)
if (this.openid == null) {
// 获取服务供应商
let that = this;
let provider = '';
uni.getProvider({
service: 'oauth',
success: function(res) {
console.log(res);
provider = res.provider[0];
// 登录微信
uni.login({
provider: provider,
success: function(loginRes) {
console.log(loginRes);
// debugger
that.request
.post('/Common/GetOpenId/', {
ciphertext: {
nvc_platform: '1',
js_code: loginRes.code
}
})
.then(res => {
console.log(res);
// debugger
that.setOpenid({
openid: res.data.openid,
session_key: res.data.session_key,
provider: provider
});
})
.catch(e => {});
// // 获取用户信息
// uni.getUserInfo({
// provider:provider,
// success:function(infoRes){
// console.log(infoRes)
// }
// })
},
fail: function(res) {}
});
}
});
}
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.wrap { .logo {
height: 200vh; display: block;
width: 282rpx;
height: 106rpx;
margin: 0 auto;
padding: 40rpx 0 60rpx;
}
.loginWarp {
padding: 0 75rpx;
.loginbtn {
margin: 70rpx 0;
}
.wxicon {
color: #52c223;
} }
}
</style> </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>
<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">
<u-cell-group>
<u-cell-item v-for="(item,index) in provinces" :title="item.label" :arrow="false" :index="index" :key="index"
@click="provinceChange">
<u-icon v-show="isChooseP&&province===index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
</u-cell-item>
</u-cell-group>
</scroll-view>
</view>
</view>
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true">
<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">
<u-icon v-show="isChooseC&&city===index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
</u-cell-item>
</u-cell-group>
</scroll-view>
</view>
</view>
<view class="area-item">
<view class="u-padding-10 u-bg-gray" style="height: 100%;">
<scroll-view :scroll-y="true">
<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">
<u-icon v-show="isChooseA&&area===index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
</u-cell-item>
</u-cell-group>
</scroll-view>
</view>
</view>
</view>
</view>
</u-popup>
</template>
<script>
import provinces from "uview-ui/libs/util/province.js";
import citys from "uview-ui/libs/util/city.js";
import areas from "uview-ui/libs/util/area.js";
/**
* city-select 省市区级联选择器
* @property {String Number} z-index 弹出时的z-index值(默认1075)
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
* @property {String} default-region 默认选中的地区,中文形式
* @property {String} default-code 默认选中的地区,编号形式
*/
export default {
name: 'u-city-select',
props: {
// 通过双向绑定控制组件的弹出与收起
value: {
type: Boolean,
default: false
},
// 默认显示的地区,可传类似["河北省", "秦皇岛市", "北戴河区"]
defaultRegion: {
type: Array,
default () {
return [];
}
},
// 默认显示地区的编码,defaultRegion和areaCode同时存在,areaCode优先,可传类似["13", "1303", "130304"]
areaCode: {
type: Array,
default () {
return [];
}
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 0
}
},
data() {
return {
cityValue: "",
isChooseP: false, //是否已经选择了省
province: 0, //省级下标
provinces: provinces,
isChooseC: false, //是否已经选择了市
city: 0, //市级下标
citys: citys[0],
isChooseA: false, //是否已经选择了区
area: 0, //区级下标
areas: areas[0][0],
tabsList: [{
name: '请选择'
}],
tabsIndex: 0,
}
},
mounted() {
this.init();
},
computed: {
isChange() {
return this.tabsIndex > 1;
},
genTabsList() {
let tabsList = [{
name: "请选择"
}];
if (this.isChooseP) {
tabsList[0]['name'] = this.provinces[this.province]['label'];
tabsList[1] = {
name: "请选择"
};
}
if (this.isChooseC) {
tabsList[1]['name'] = this.citys[this.city]['label'];
tabsList[2] = {
name: "请选择"
};
}
if (this.isChooseA) {
tabsList[2]['name'] = this.areas[this.area]['label'];
}
return tabsList;
},
uZIndex() {
// 如果用户有传递z-index值,优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
}
},
methods: {
init() {
if (this.areaCode.length) {
this.setProvince("", this.areaCode[0]);
this.setCity("", this.areaCode[1]);
this.setArea("", this.areaCode[2]);
} else if (this.defaultRegion.length) {
this.setProvince(this.defaultRegion[0], "");
this.setCity(this.defaultRegion[1], "");
this.setArea(this.defaultRegion[2], "");
};
},
setProvince(label = "", value = "") {
this.provinces.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.provinceChange(k);
}
})
},
setCity(label = "", value = "") {
this.citys.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.cityChange(k);
}
})
},
setArea(label = "", value = "") {
this.areas.map((v, k) => {
if (value ? v.value == value : v.label == label) {
this.isChooseA = true;
this.area = k;
}
})
},
close() {
this.$emit('input', false);
},
tabsChange(index) {
this.tabsIndex = index;
},
provinceChange(index) {
this.isChooseP = true;
this.isChooseC = false;
this.isChooseA = false;
this.province = index;
this.citys = citys[index];
this.tabsIndex = 1;
},
cityChange(index) {
this.isChooseC = true;
this.isChooseA = false;
this.city = index;
this.areas = areas[this.province][index];
this.tabsIndex = 2;
},
areaChange(index) {
this.isChooseA = true;
this.area = index;
let result = {};
result.province = this.provinces[this.province];
result.city = this.citys[this.city];
result.area = this.areas[this.area];
this.$emit('city-change', result);
this.close();
}
}
}
</script>
<style lang="scss">
.area-box {
width: 100%;
overflow: hidden;
height: 800rpx;
>view {
width: 150%;
transition: transform 0.3s ease-in-out 0s;
transform: translateX(0);
&.change {
transform: translateX(-33.3333333%);
}
}
.area-item {
width: 33.3333333%;
height: 800rpx;
}
}
</style>
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
:maxlength="6" :maxlength="6"
:dot-fill="true" :dot-fill="true"
v-model="password" v-model="password"
:disabled-keyboard="false" :disabled-keyboard="true"
></u-message-input> ></u-message-input>
</view> </view>
<view class="u-text-center u-padding-top-10 u-padding-bottom-20 tips">支付键盘</view> <view class="u-text-center u-padding-top-10 u-padding-bottom-20 tips">支付键盘</view>
......
...@@ -142,16 +142,16 @@ export default { ...@@ -142,16 +142,16 @@ export default {
// 初始化 // 初始化
this.cropper = new WeCropper(this.cropperOpt) this.cropper = new WeCropper(this.cropperOpt)
.on('ready', ctx => { .on('ready', ctx => {
// console.log(`wecropper is ready for work!`) // wecropper is ready for work!
}) })
.on('beforeImageLoad', ctx => { .on('beforeImageLoad', ctx => {
// console.log(`before picture loaded, i can do something`) // before picture loaded, i can do something
}) })
.on('imageLoad', ctx => { .on('imageLoad', ctx => {
// console.log(`picture loaded`) // picture loaded
}) })
.on('beforeDraw', (ctx, instance) => { .on('beforeDraw', (ctx, instance) => {
// console.log(`before canvas draw,i can do something`) // before canvas draw,i can do something
}); });
// 设置导航栏样式,以免用户在page.json中没有设置为黑色背景 // 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
uni.setNavigationBarColor({ uni.setNavigationBarColor({
......
...@@ -479,7 +479,7 @@ ...@@ -479,7 +479,7 @@
padding: 40rpx 0 40rpx 0; padding: 40rpx 0 40rpx 0;
&__icon { &__icon {
margin: 0 10rpx; margin: 0 16rpx;
} }
&__text { &__text {
......
...@@ -2,13 +2,14 @@ ...@@ -2,13 +2,14 @@
<view <view
class="u-card" class="u-card"
@tap.stop="click" @tap.stop="click"
:class="{ 'u-border': border, 'u-card-full': full }" :class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
:style="{ :style="{
borderRadius: full ? 0 : borderRadius + 'rpx', borderRadius: borderRadius + 'rpx',
margin: margin margin: margin
}" }"
> >
<view <view
v-if="showHead"
class="u-card__head" class="u-card__head"
:style="[headStyle, {padding: padding + 'rpx'}]" :style="[headStyle, {padding: padding + 'rpx'}]"
:class="{ :class="{
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
</view> </view>
<view @tap="bodyClick" class="u-card__body" :style="[bodyStyle, {padding: padding + 'rpx'}]"><slot name="body" /></view> <view @tap="bodyClick" class="u-card__body" :style="[bodyStyle, {padding: padding + 'rpx'}]"><slot name="body" /></view>
<view <view
v-if="showFoot"
class="u-card__foot" class="u-card__foot"
@tap="footClick" @tap="footClick"
:style="[footStyle, {padding: $slots.foot ? padding + 'rpx' : 0}]" :style="[footStyle, {padding: $slots.foot ? padding + 'rpx' : 0}]"
...@@ -88,6 +90,8 @@ ...@@ -88,6 +90,8 @@
* @property {Object} foot-style 底部自定义样式,对象形式 * @property {Object} foot-style 底部自定义样式,对象形式
* @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true) * @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
* @property {Boolean} foot-border-top 是否显示底部的上边框(默认true) * @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
* @property {Boolean} show-head 是否显示头部(默认true)
* @property {Boolean} show-head 是否显示尾部(默认true)
* @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径 * @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
* @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60) * @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60)
* @property {Boolean} thumb-circle 缩略图是否为圆形(默认false) * @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
...@@ -205,6 +209,16 @@ export default { ...@@ -205,6 +209,16 @@ export default {
padding: { padding: {
type: [String, Number], type: [String, Number],
default: '30' default: '30'
},
// 是否显示头部
showHead: {
type: Boolean,
default: true
},
// 是否显示尾部
showFoot: {
type: Boolean,
default: true
} }
}, },
data() { data() {
...@@ -241,8 +255,8 @@ export default { ...@@ -241,8 +255,8 @@ export default {
margin-right: 0 !important; margin-right: 0 !important;
} }
&:after { &--border:after {
border-radius: 20rpx; border-radius: 16rpx;
} }
&__head { &__head {
......
<template> <template>
<view class="u-collapse-item" :style="[itemStyle]"> <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 :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' }, <block v-if="!$slots['title-all']">
isShow && activeStyle && !arrow ? activeStyle : '']"> <view v-if="!$slots['title']" class="u-collapse-title u-line-1" :style="[{ textAlign: align ? align : 'left' },
{{ title }} isShow && activeStyle && !arrow ? activeStyle : '']">
</view> {{ title }}
<view class="u-icon-wrap"> </view>
<u-icon v-if="arrow" :color="arrowColor ? arrowColor : $u.color.tipsColor" :class="{ 'u-arrow-down-icon-active': isShow }" <slot v-else name="title" />
class="u-arrow-down-icon" name="arrow-down"></u-icon> <view class="u-icon-wrap">
</view> <u-icon v-if="arrow" :color="arrowColor ? arrowColor : $u.color.tipsColor" :class="{ 'u-arrow-down-icon-active': isShow }"
class="u-arrow-down-icon" name="arrow-down"></u-icon>
</view>
</block>
<slot v-else name="title-all" />
</view> </view>
<view class="u-collapse-body" :style="[{ <view class="u-collapse-body" :style="[{
height: isShow ? height + 'px' : '0' height: isShow ? height + 'px' : '0'
...@@ -108,6 +112,7 @@ ...@@ -108,6 +112,7 @@
} }
}, },
created() { created() {
// 获取u-collapse的信息,放在u-collapse是为了方便,不用每个u-collapse-item写一遍
this.isShow = this.open; this.isShow = this.open;
this.nameSync = this.name ? this.name : this.uCollapse.childrens.length; this.nameSync = this.name ? this.name : this.uCollapse.childrens.length;
this.uCollapse.childrens.push(this); this.uCollapse.childrens.push(this);
...@@ -169,12 +174,12 @@ ...@@ -169,12 +174,12 @@
.u-collapse-title { .u-collapse-title {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
margin-right: 14rpx;
} }
.u-arrow-down-icon { .u-arrow-down-icon {
transition: all 0.3s; transition: all 0.3s;
margin-right: 24rpx; margin-right: 20rpx;
margin-left: 14rpx;
} }
.u-arrow-down-icon-active { .u-arrow-down-icon-active {
......
...@@ -4,15 +4,15 @@ ...@@ -4,15 +4,15 @@
flexDirection: labelPosition == 'left' ? 'row' : 'column' flexDirection: labelPosition == 'left' ? 'row' : 'column'
}"> }">
<view class="u-form-item--left" :style="{ <view class="u-form-item--left" :style="{
width: labelPosition == 'left' ? labelWidth + 'rpx' : '100%', width: labelPosition == 'left' ? getLabelWidth : '100%',
flex: `0 0 ${labelPosition == 'left' ? labelWidth + 'rpx' : '100%'}`, flex: `0 0 ${labelPosition == 'left' ? getLabelWidth : '100%'}`,
marginBottom: labelPosition == 'left' ? 0 : '10rpx', marginBottom: labelPosition == 'left' ? 0 : '10rpx',
}"> }">
<!-- 为了块对齐 --> <!-- 为了块对齐 -->
<view class="u-form-item--left__content"> <view class="u-form-item--left__content">
<!-- nvue不支持伪元素before --> <!-- nvue不支持伪元素before -->
<text v-if="isRequired" class="u-form-item--left__content--required">*</text> <text v-if="required" class="u-form-item--left__content--required">*</text>
<view class="u-form-item--left__content__icon" v-if="leftIcon"> <view class="u-form-item--left__content__icon" v-if="leftIcon">
<u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon> <u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
</view> </view>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
</view> </view>
</view> </view>
<view class="u-form-item__message" v-if="validateState === 'error' && showError('message')" :style="{ <view class="u-form-item__message" v-if="validateState === 'error' && showError('message')" :style="{
paddingLeft: labelPosition == 'left' ? `${labelWidth}rpx` : '0', paddingLeft: labelPosition == 'left' ? getLabelWidth : '0',
}">{{validateMessage}}</view> }">{{validateMessage}}</view>
</view> </view>
</template> </template>
...@@ -117,12 +117,17 @@ export default { ...@@ -117,12 +117,17 @@ export default {
default() { default() {
return {} return {}
} }
},
// 是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置
required: {
type: Boolean,
default: false
} }
}, },
data() { data() {
return { return {
initialValue: '', // 存储的默认值 initialValue: '', // 存储的默认值
isRequired: false, // 是否必填 // isRequired: false, // 是否必填,由于人性化考虑,必填"*"号通过props的required配置,不再通过rules的规则自动生成
validateState: '', // 是否校验成功 validateState: '', // 是否校验成功
validateMessage: '' ,// 校验失败的提示语 validateMessage: '' ,// 校验失败的提示语
// 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色, // 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色,
...@@ -146,11 +151,15 @@ export default { ...@@ -146,11 +151,15 @@ export default {
}, },
showError() { showError() {
return type => { return type => {
// 如果errorType数组中含有none,就不提示错误信息 // 如果errorType数组中含有none,或者toast提示类型
if(this.errorType.indexOf('none') >= 0) return false; if(this.errorType.indexOf('none') >= 0) return false;
else if(this.errorType.indexOf(type) >= 0) return true; else if(this.errorType.indexOf(type) >= 0) return true;
else return false; else return false;
} }
},
// 获取labelWidth的值
getLabelWidth() {
return this.labelWidth == 'auto' ? 'auto' : this.labelWidth + 'rpx';
} }
}, },
methods: { methods: {
...@@ -161,14 +170,15 @@ export default { ...@@ -161,14 +170,15 @@ export default {
// 判断是否需要required校验 // 判断是否需要required校验
setRules() { setRules() {
let that = this; let that = this;
// 由于人性化考虑,必填"*"号通过props的required配置,不再通过rules的规则自动生成
// 从父组件u-form拿到当前u-form-item需要验证 的规则 // 从父组件u-form拿到当前u-form-item需要验证 的规则
let rules = this.getRules(); // let rules = this.getRules();
if (rules.length) { // if (rules.length) {
this.isRequired = rules.some(rule => { // this.isRequired = rules.some(rule => {
// 如果有必填项,就返回,没有的话,就是undefined // // 如果有必填项,就返回,没有的话,就是undefined
return rule.required; // return rule.required;
}); // });
} // }
// blur事件 // blur事件
this.$on('on-form-blur', that.onFieldBlur); this.$on('on-form-blur', that.onFieldBlur);
...@@ -201,9 +211,9 @@ export default { ...@@ -201,9 +211,9 @@ export default {
// 整体验证表单时,triggerType为空字符串,此时返回所有规则进行验证 // 整体验证表单时,triggerType为空字符串,此时返回所有规则进行验证
if(!triggerType) return rules; if(!triggerType) return rules;
// 历遍判断规则是否有对应的事件,比如blur,change触发等的事件 // 历遍判断规则是否有对应的事件,比如blur,change触发等的事件
// return rules.filter(res => res.trigger == triggerType); // 使用indexOf判断,是因为某些时候设置的验证规则的trigger属性可能为多个,比如['blur','change']
// 使用indexOf判断,是因为某些时候设置的验证规则的trigger属性可能为多个,比如"blur,change" // 某些场景可能的判断规则,可能不存在trigger属性,故先判断是否存在此属性
return rules.filter(res => !res.trigger || res.trigger.indexOf(triggerType) !== -1); return rules.filter(res => res.trigger && res.trigger.indexOf(triggerType) !== -1);
}, },
// 校验数据 // 校验数据
...@@ -245,14 +255,17 @@ export default { ...@@ -245,14 +255,17 @@ export default {
this.errorType = this.uForm.errorType; this.errorType = this.uForm.errorType;
// 设置初始值 // 设置初始值
this.initialValue = this.fieldValue; this.initialValue = this.fieldValue;
// 添加表单校验 // 添加表单校验,这里必须要写在$nextTick中,因为u-form的rules是通过ref手动传入的
this.setRules(); // 不在$nextTick中的话,可能会造成执行此处代码时,父组件还没通过ref把规则给u-form,导致规则为空
this.$nextTick(() =>{
this.setRules();
})
}, },
// 组件销毁前,将实例从 Form 的缓存中移除 // 组件销毁前,将实例从 Form 的缓存中移除
beforeDestroy() { beforeDestroy() {
this.dispatch('u-form', 'on-form-item-remove', this); this.dispatch('u-form', 'on-form-item-remove', this);
} },
}; };
</script> </script>
......
...@@ -25,7 +25,7 @@ export default { ...@@ -25,7 +25,7 @@ export default {
errorType: { errorType: {
type: Array, type: Array,
default() { default() {
return ['message'] return ['message', 'toast']
} }
} }
}, },
...@@ -75,14 +75,22 @@ export default { ...@@ -75,14 +75,22 @@ export default {
// 对所有的u-form-item进行校验 // 对所有的u-form-item进行校验
let valid = true; // 默认通过 let valid = true; // 默认通过
let count = 0; // 用于标记是否检查完毕 let count = 0; // 用于标记是否检查完毕
let errorArr = []; // 存放错误信息
this.fields.map(field => { this.fields.map(field => {
// 调用每一个u-form-item实例的validation的校验方法 // 调用每一个u-form-item实例的validation的校验方法
field.validation('', error => { field.validation('', error => {
// 如果任意一个u-form-item校验不通过,就意味着整个表单不通过 // 如果任意一个u-form-item校验不通过,就意味着整个表单不通过
if (error) valid = false; if (error) {
valid = false;
errorArr.push(error);
}
// 当历遍了所有的u-form-item时,调用promise的then方法 // 当历遍了所有的u-form-item时,调用promise的then方法
if (++count === this.fields.length) { if (++count === this.fields.length) {
resolve(valid); // 进入promise的then方法 resolve(valid); // 进入promise的then方法
// 判断是否设置了toast的提示方式,只提示最前面的表单域的第一个错误信息
if(this.errorType.indexOf('none') === -1 && this.errorType.indexOf('toast') >= 0) {
this.$u.toast(errorArr[0]);
}
// 调用回调方法 // 调用回调方法
if (typeof callback == 'function') callback(valid); if (typeof callback == 'function') callback(valid);
} }
......
...@@ -258,7 +258,7 @@ export default { ...@@ -258,7 +258,7 @@ export default {
this.$emit('confirm', e.detail.value); this.$emit('confirm', e.detail.value);
}, },
onClear(event) { onClear(event) {
this.$emit('input'); this.$emit('input', '');
}, },
inputClick() { inputClick() {
this.$emit('click'); this.$emit('click');
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
//当前页面背景颜色,如果背景为非白色的时候,需要把此值设置为背景的颜色 //当前页面背景颜色,如果背景为非白色的时候,需要把此值设置为背景的颜色
bgColor: { bgColor: {
type: String, type: String,
default: '#fff' default: '#ffffff'
}, },
// 是否显示加载中的图标 // 是否显示加载中的图标
icon: { icon: {
......
<template> <template>
<view class=""> <view class="">
<view class="u-navbar" :style="[navbarStyle]" :class="{'u-navbar-fixed': isFixed, 'u-border-bottom': borderBottom}"> <view class="u-navbar" :style="[navbarStyle]" :class="{ 'u-navbar-fixed': isFixed, 'u-border-bottom': borderBottom }">
<view class="u-status-bar" :style="{ height: statusBarHeight + 'px' }"></view> <view class="u-status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
<view class="u-navbar-inner" :style="[navbarInnerStyle]"> <view class="u-navbar-inner" :style="[navbarInnerStyle]">
<view class="u-back-wrap" v-if="isBack" @tap="goBack"> <view class="u-back-wrap" v-if="isBack" @tap="goBack">
<view class="u-icon-wrap"> <view class="u-icon-wrap"><u-icon :name="backIconName" :color="backIconColor" :size="backIconSize"></u-icon></view>
<u-icon :name="backIconName" :color="backIconColor" :size="backIconSize"></u-icon> <view class="u-icon-wrap u-back-text u-line-1" v-if="backText" :style="[backTextStyle]">{{ backText }}</view>
</view>
<view class="u-icon-wrap u-back-text u-line-1" v-if="backText" :style="[backTextStyle]">
{{backText}}
</view>
</view> </view>
<view class="u-navbar-content-title" v-if="title" :style="[titleStyle]"> <view class="u-navbar-content-title" v-if="title" :style="[titleStyle]">
<view class="u-title u-line-1" :style="{ <view
color: titleColor, class="u-title u-line-1"
fontSize: titleSize + 'rpx' :style="{
}"> color: titleColor,
{{title}} fontSize: titleSize + 'rpx'
}"
>
{{ title }}
</view> </view>
</view> </view>
<view class="u-slot-content"> <view class="u-slot-content"><slot></slot></view>
<slot></slot> <view class="u-slot-right"><slot name="right"></slot></view>
</view>
<view class="u-slot-right">
<slot name="right"></slot>
</view>
</view> </view>
</view> </view>
<!-- 解决fixed定位后导航栏塌陷的问题 --> <!-- 解决fixed定位后导航栏塌陷的问题 -->
<view class="u-navbar-placeholder" v-if="isFixed" :style="{width: '100%',height: Number(navbarHeight) + statusBarHeight + 'px'}"> <view class="u-navbar-placeholder" v-if="isFixed" :style="{ width: '100%', height: Number(navbarHeight) + statusBarHeight + 'px' }"></view>
</view>
</view> </view>
</template> </template>
...@@ -39,7 +32,7 @@ ...@@ -39,7 +32,7 @@
let systemInfo = uni.getSystemInfoSync(); let systemInfo = uni.getSystemInfoSync();
let menuButtonInfo = {}; let menuButtonInfo = {};
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容) // 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
// #ifdef MP // #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
menuButtonInfo = uni.getMenuButtonBoundingClientRect(); menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif // #endif
/** /**
...@@ -56,12 +49,13 @@ menuButtonInfo = uni.getMenuButtonBoundingClientRect(); ...@@ -56,12 +49,13 @@ menuButtonInfo = uni.getMenuButtonBoundingClientRect();
* @property {String Number} title-width 导航栏标题的最大宽度,内容超出会以省略号隐藏,单位rpx(默认250) * @property {String Number} title-width 导航栏标题的最大宽度,内容超出会以省略号隐藏,单位rpx(默认250)
* @property {String} title-color 标题的颜色(默认#606266) * @property {String} title-color 标题的颜色(默认#606266)
* @property {String Number} title-size 导航栏标题字体大小,单位rpx(默认32) * @property {String Number} title-size 导航栏标题字体大小,单位rpx(默认32)
* @property {Function} custom-back 自定义返回逻辑方法
* @property {String Number} z-index 固定在顶部时的z-index值(默认980) * @property {String Number} z-index 固定在顶部时的z-index值(默认980)
* @property {Boolean} is-back 是否显示导航栏左边返回图标和辅助文字(默认true) * @property {Boolean} is-back 是否显示导航栏左边返回图标和辅助文字(默认true)
* @property {Object} background 导航栏背景设置,见官网说明(默认{ background: '#ffffff' }) * @property {Object} background 导航栏背景设置,见官网说明(默认{ background: '#ffffff' })
* @property {Boolean} is-fixed 导航栏是否固定在顶部(默认true) * @property {Boolean} is-fixed 导航栏是否固定在顶部(默认true)
* @property {Boolean} border-bottom 导航栏底部是否显示下边框,如定义了较深的背景颜色,可取消此值(默认true) * @property {Boolean} border-bottom 导航栏底部是否显示下边框,如定义了较深的背景颜色,可取消此值(默认true)
* @example <u-navbar back-text="返回" title="剑未配妥,出门已是江湖"></u-navbar> * @example <u-navbar back-text="返回" title="剑未配妥,出门已是江湖"></u-navbar>
*/ */
export default { export default {
name: "u-navbar", name: "u-navbar",
...@@ -146,6 +140,11 @@ export default { ...@@ -146,6 +140,11 @@ export default {
zIndex: { zIndex: {
type: [String, Number], type: [String, Number],
default: '' default: ''
},
// 自定义返回逻辑
customBack: {
type: Function,
default: null
} }
}, },
data() { data() {
...@@ -208,82 +207,87 @@ export default { ...@@ -208,82 +207,87 @@ export default {
created() {}, created() {},
methods: { methods: {
goBack() { goBack() {
uni.navigateBack(); // 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑
if(typeof this.customBack === 'function') {
this.customBack();
} {
uni.navigateBack();
}
} }
} }
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.u-navbar { .u-navbar {
width: 100%; width: 100%;
} }
.u-navbar-fixed { .u-navbar-fixed {
position: fixed; position: fixed;
left: 0; left: 0;
right: 0; right: 0;
top: 0; top: 0;
z-index: 991; z-index: 991;
} }
.u-status-bar { .u-status-bar {
width: 100%; width: 100%;
} }
.u-navbar-inner { .u-navbar-inner {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
position: relative; position: relative;
align-items: center; align-items: center;
} }
.u-back-wrap { .u-back-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
flex: 1; flex: 1;
flex-grow: 0; flex-grow: 0;
padding: 14rpx 14rpx 14rpx 24rpx; padding: 14rpx 14rpx 14rpx 24rpx;
} }
.u-back-text { .u-back-text {
padding-left: 4rpx; padding-left: 4rpx;
font-size: 30rpx; font-size: 30rpx;
} }
.u-navbar-content-title { .u-navbar-content-title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex: 1; flex: 1;
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
height: 60rpx; height: 60rpx;
text-align: center; text-align: center;
flex-shrink: 0; flex-shrink: 0;
} }
.u-navbar-centent-slot { .u-navbar-centent-slot {
flex: 1; flex: 1;
} }
.u-title { .u-title {
line-height: 1; line-height: 1;
font-size: 32rpx; font-size: 32rpx;
flex: 1; flex: 1;
} }
.u-navbar-right { .u-navbar-right {
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
} }
.u-slot-content { .u-slot-content {
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
} }
</style> </style>
...@@ -140,7 +140,7 @@ ...@@ -140,7 +140,7 @@
}, },
data() { data() {
return { return {
inputVal: 0 // 输入框中的值,不能直接使用props中的value,因为应该改变props的状态 inputVal: 1 // 输入框中的值,不能直接使用props中的value,因为应该改变props的状态
}; };
}, },
created() { created() {
......
...@@ -27,15 +27,15 @@ ...@@ -27,15 +27,15 @@
<slot /> <slot />
</view> </view>
<block v-else><slot /></block> <block v-else><slot /></block>
<u-icon <view class="u-close" :class="['u-close--' + closeIconPos]">
v-if="mode != 'center' && closeable" <u-icon
@click="close" v-if="mode != 'center' && closeable"
class="u-close" @click="close"
:class="['u-close--' + closeIconPos]" :name="closeIcon"
:name="closeIcon" :color="closeIconColor"
:color="closeIconColor" :size="closeIconSize"
:size="closeIconSize" ></u-icon>
></u-icon> </view>
</view> </view>
</view> </view>
</template> </template>
...@@ -176,18 +176,17 @@ export default { ...@@ -176,18 +176,17 @@ export default {
// 判断是否是否百分比或者auto值,是的话,直接使用该值,否则默认为rpx单位的数值 // 判断是否是否百分比或者auto值,是的话,直接使用该值,否则默认为rpx单位的数值
let length = /%$/.test(this.length) || this.length == 'auto' ? this.length : uni.upx2px(this.length) + 'px'; let length = /%$/.test(this.length) || this.length == 'auto' ? this.length : uni.upx2px(this.length) + 'px';
// 如果是左边或者上边弹出时,需要给translate设置为负值,用于隐藏 // 如果是左边或者上边弹出时,需要给translate设置为负值,用于隐藏
if (this.mode == 'left' || this.mode == 'top') translate = length == 'auto' ? '-100%' : '-' + length;
if (this.mode == 'left' || this.mode == 'right') { if (this.mode == 'left' || this.mode == 'right') {
style = { style = {
width: length, width: length,
height: '100%', height: '100%',
transform: `translate3D(${translate},0px,0px)` transform: `translate3D(${this.mode == 'left' ? '-100%' : '100%'},0px,0px)`
}; };
} else if (this.mode == 'top' || this.mode == 'bottom') { } else if (this.mode == 'top' || this.mode == 'bottom') {
style = { style = {
width: '100%', width: '100%',
height: length, height: length,
transform: `translate3D(0px,${translate},0px)` transform: `translate3D(0px,${this.mode == 'top' ? '-100%' : '100%'},0px)`
}; };
} }
style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.popup; style.zIndex = this.zIndex ? this.zIndex : this.$u.zIndex.popup;
...@@ -236,13 +235,6 @@ export default { ...@@ -236,13 +235,6 @@ export default {
} }
} }
}, },
created() {
// 先让弹窗组件渲染,再改变遮罩和抽屉元素的样式,让其动画其起作用(必须要有延时,才会有效果)
this.visibleSync = this.value;
setTimeout(() => {
this.showDrawer = this.value;
}, 30);
},
methods: { methods: {
// 遮罩被点击 // 遮罩被点击
maskClick() { maskClick() {
...@@ -266,15 +258,25 @@ export default { ...@@ -266,15 +258,25 @@ export default {
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件 // 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
if (this.popup == true) this.$emit('input', status); if (this.popup == true) this.$emit('input', status);
this[param1] = status; this[param1] = status;
if (this.timer) { if(status) {
clearTimeout(this.timer); // #ifdef H5 || MP
} this.timer = setTimeout(() => {
this.timer = setTimeout(() => { this[param2] = status;
this.$emit(status ? 'open' : 'close');
}, 50);
// #endif
// #ifndef H5 || MP
this.$nextTick(() => {
this[param2] = status; this[param2] = status;
this.$emit(status ? 'open' : 'close'); this.$emit(status ? 'open' : 'close');
}, })
status ? 30 : 300 // #endif
); } else {
this.timer = setTimeout(() => {
this[param2] = status;
this.$emit(status ? 'open' : 'close');
}, 300);
}
} }
} }
}; };
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
height: height + 'rpx' height: height + 'rpx'
}" }"
> >
<view class="u-icon-wrap"><u-icon class="u-clear-icon" :size="30" name="search" :color="searchIconColor ? searchIconColor : color"></u-icon></view> <view class="u-icon-wrap">
<u-icon class="u-clear-icon" :size="30" :name="searchIcon" :color="searchIconColor ? searchIconColor : color"></u-icon>
</view>
<input <input
confirm-type="search" confirm-type="search"
@blur="blur" @blur="blur"
...@@ -29,7 +31,8 @@ ...@@ -29,7 +31,8 @@
type="text" type="text"
:style="[{ :style="[{
textAlign: inputAlign, textAlign: inputAlign,
color: color color: color,
backgroundColor: bgColor,
}, inputStyle]" }, inputStyle]"
/> />
<view class="u-close-wrap" v-if="keyword && clearabled && focused" @touchstart="clear"> <view class="u-close-wrap" v-if="keyword && clearabled && focused" @touchstart="clear">
...@@ -58,10 +61,12 @@ ...@@ -58,10 +61,12 @@
* @property {String} action-text 右侧控件文字(默认“搜索”) * @property {String} action-text 右侧控件文字(默认“搜索”)
* @property {Object} action-style 右侧控件的样式,对象形式 * @property {Object} action-style 右侧控件的样式,对象形式
* @property {String} input-align 输入框内容水平对齐方式(默认left) * @property {String} input-align 输入框内容水平对齐方式(默认left)
* @property {Object} input-style 自定义输入框样式,对象形式
* @property {Boolean} disabled 是否启用输入框(默认false) * @property {Boolean} disabled 是否启用输入框(默认false)
* @property {String} search-icon-color 搜索图标的颜色,默认同输入框字体颜色 * @property {String} search-icon-color 搜索图标的颜色,默认同输入框字体颜色
* @property {String} color 输入框字体颜色(默认#606266) * @property {String} color 输入框字体颜色(默认#606266)
* @property {String} placeholder-color placeholder的颜色(默认#909399) * @property {String} placeholder-color placeholder的颜色(默认#909399)
* @property {String} search-icon 输入框左边的图标,可以为uView图标名称或图片路径
* @property {String} margin 组件与其他上下左右元素之间的距离,带单位的字符串形式,如"30rpx" * @property {String} margin 组件与其他上下左右元素之间的距离,带单位的字符串形式,如"30rpx"
* @property {Boolean} animation 是否开启动画,见上方说明(默认false) * @property {Boolean} animation 是否开启动画,见上方说明(默认false)
* @property {String} value 输入框初始值 * @property {String} value 输入框初始值
...@@ -180,6 +185,11 @@ export default { ...@@ -180,6 +185,11 @@ export default {
margin: { margin: {
type: String, type: String,
default: '0' default: '0'
},
// 左边输入框的图标,可以为uView图标名称或图片路径
searchIcon: {
type: String,
default: 'search'
} }
}, },
data() { data() {
...@@ -231,11 +241,14 @@ export default { ...@@ -231,11 +241,14 @@ export default {
// 也可以作为用户通过this.$refs形式调用清空输入框内容 // 也可以作为用户通过this.$refs形式调用清空输入框内容
clear() { clear() {
this.keyword = ''; this.keyword = '';
this.$emit('clear'); // 延后发出事件,避免在父组件监听clear事件时,value为更新前的值(不为空)
this.$nextTick(() => {
this.$emit('clear');
})
}, },
// 确定搜索 // 确定搜索
search() { search(e) {
this.$emit('search', this.keyword); this.$emit('search', e.detail.value);
// 收起键盘 // 收起键盘
uni.hideKeyboard(); uni.hideKeyboard();
}, },
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
// 是否显示左边的竖条 // 是否显示左边的竖条
showLine: { showLine: {
type: Boolean, type: Boolean,
default: false default: true
} }
}, },
data() { data() {
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
width: width + 'rpx', width: width + 'rpx',
height: width + 'rpx' height: width + 'rpx'
}"> }">
<u-icon name="plus" class="u-add-btn" size="40" @click="selectFile"></u-icon> <u-icon name="plus" class="u-add-btn" size="40"></u-icon>
<view class="u-add-tips">{{uploadText}}</view> <view class="u-add-tips">{{uploadText}}</view>
</view> </view>
</view> </view>
...@@ -462,6 +462,7 @@ ...@@ -462,6 +462,7 @@
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 10rpx;
} }
.u-delete-icon { .u-delete-icon {
......
...@@ -46,6 +46,11 @@ ...@@ -46,6 +46,11 @@
keepRunning: { keepRunning: {
type: Boolean, type: Boolean,
default: false default: false
},
// 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
uniqueKey: {
type: String,
default: ''
} }
}, },
data() { data() {
...@@ -69,15 +74,17 @@ ...@@ -69,15 +74,17 @@
methods: { methods: {
checkKeepRunning() { checkKeepRunning() {
// 获取上一次退出页面(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空 // 获取上一次退出页面(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空
let lastTimestamp = Number(uni.getStorageSync('$uCountDownTimestamp')); let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'));
if(!lastTimestamp) return this.changeEvent(this.startText);
// 当前秒的时间戳 // 当前秒的时间戳
let nowTimestamp = Math.floor((+ new Date()) / 1000); let nowTimestamp = Math.floor((+ new Date()) / 1000);
// 判断当前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳 // 判断当前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳
console.log(lastTimestamp, nowTimestamp);
if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) { if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
// 剩余尚未执行完的倒计秒数 // 剩余尚未执行完的倒计秒数
this.secNum = lastTimestamp - nowTimestamp; this.secNum = lastTimestamp - nowTimestamp;
// 清除本地保存的变量 // 清除本地保存的变量
uni.setStorageSync('$uCountDownTimestamp', 0); uni.setStorageSync(this.uniqueKey + '_$uCountDownTimestamp', 0);
// 开始倒计时 // 开始倒计时
this.start(); this.start();
} else { } else {
...@@ -92,11 +99,11 @@ ...@@ -92,11 +99,11 @@
clearInterval(this.timer); clearInterval(this.timer);
this.timer = null; this.timer = null;
} }
//this.secNum = this.seconds;
this.$emit('start'); this.$emit('start');
this.canGetCode = false; this.canGetCode = false;
// 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示 // 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示
this.changeEvent(this.changeText.replace(/x|X/, this.secNum)); this.changeEvent(this.changeText.replace(/x|X/, this.secNum));
this.setTimeToStorage();
this.timer = setInterval(() => { this.timer = setInterval(() => {
if (--this.secNum) { if (--this.secNum) {
// 用当前倒计时的秒数替换提示字符串中的"x"字母 // 用当前倒计时的秒数替换提示字符串中的"x"字母
...@@ -109,7 +116,6 @@ ...@@ -109,7 +116,6 @@
this.$emit('end'); this.$emit('end');
this.canGetCode = true; this.canGetCode = true;
} }
this.setTimeToStorage();
}, 1000); }, 1000);
}, },
// 重置,可以让用户再次获取验证码 // 重置,可以让用户再次获取验证码
...@@ -124,15 +130,15 @@ ...@@ -124,15 +130,15 @@
}, },
// 保存时间戳,为了防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来 // 保存时间戳,为了防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来
setTimeToStorage() { setTimeToStorage() {
if(!this.keepRunning) return ; if(!this.keepRunning || !this.timer) return console.log(111, this.timer);
// 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时 // 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时
// 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理 // 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理
if(this.secNum > 0 && this.secNum < this.seconds) { if(this.secNum > 0 && this.secNum <= this.seconds) {
// 获取当前时间戳(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分 // 获取当前时间戳(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分
let nowTimestamp = Math.floor((+ new Date()) / 1000); let nowTimestamp = Math.floor((+ new Date()) / 1000);
// 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数 // 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数
uni.setStorage({ uni.setStorage({
key: '$uCountDownTimestamp', key: this.uniqueKey + '_$uCountDownTimestamp',
data: nowTimestamp + this.secNum data: nowTimestamp + this.secNum
}) })
} }
...@@ -140,9 +146,9 @@ ...@@ -140,9 +146,9 @@
}, },
// 组件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除 // 组件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除
beforeDestroy() { beforeDestroy() {
this.setTimeToStorage();
clearTimeout(this.timer); clearTimeout(this.timer);
this.timer = null; this.timer = null;
this.setTimeToStorage();
} }
} }
</script> </script>
......
...@@ -53,6 +53,11 @@ u-grid { ...@@ -53,6 +53,11 @@ u-grid {
width: 100%; width: 100%;
flex: 0 0 100%; flex: 0 0 100%;
} }
// 避免小程序线条组件因为父组件display: flex;而失效
u-line {
flex: 1;
}
/* #endif */ /* #endif */
/* end-微信小程序编译后页面有组件名的元素,特别处理--end */ /* end-微信小程序编译后页面有组件名的元素,特别处理--end */
......
// 此版本发布于2020-06-10 // 此版本发布于2020-06-15
let version = '1.3.3'; let version = '1.3.5';
export default { export default {
v: version, v: version,
......
...@@ -16,7 +16,7 @@ function mobile(value) { ...@@ -16,7 +16,7 @@ function mobile(value) {
* 验证URL格式 * 验证URL格式
*/ */
function url(value) { function url(value) {
return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-z_!~*'()-]+.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].[a-z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+\/?)$/ return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
.test(value) .test(value)
} }
......
{ {
"name": "uview-ui", "name": "uview-ui",
"version": "1.3.3", "version": "1.3.5",
"description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水", "description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水",
"main": "index.js", "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"], "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