Commit ead9b90c authored by wlxuqu's avatar wlxuqu

1. Picker选择器组件新增单列和多列模式

2. Waterfall瀑布流组件新增清空和移除数据的组件方法
3. 重构圆型进度条组件,解决微信小程序可能报错的问题,新增动态减少百分比的功能
4. 新增Keyboard键盘组件无遮罩时,可以点击透明层关闭键盘的特性
5. MessageInput验证码输入框组件新增disabled-keyboard参数,用于禁止原生键盘
6. 修复Navbar自定义导航栏title-size参数无效的问题
7. 修复NumberBox步进器组件无法减到0的问题,添加cursor-spacing参数
8. 优化Tabs组件初次加载时的动画问题以及动态修改标签长度时重置current值
9. 优化Tag标签组件的内部逻辑
10. 修复slider滑块无法触发moving事件的问题
11. 优化NoticeBar横线滚动通知的事件问题
parent a8050ed4
......@@ -114,7 +114,7 @@
"template" : "template.h5.html",
"router" : {
"mode" : "hash",
"base" : "/h5/"
"base" : ""
},
"optimization" : {
"treeShaking" : {
......
......@@ -6,7 +6,7 @@
// "current": 0, //当前激活的模式(list 的索引项)
// "list": [{
// "name": "test", //模式名称
// "path": "pages/componentsB/line/index", //启动页面,必选
// "path": "pages/componentsC/test/index", //启动页面,必选
// "query": "id=1&name=2" //启动参数,在页面的-+onLoad函数里面得到
// }]
// },
......
......@@ -3,24 +3,30 @@
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="u-demo-result-line">
{{input ? input : 'Picker值'}}
</view>
<u-picker :mode="mode" :defaultTime="defaultTime" v-model="show"
:defaultRegion="defaultRegion" :params="params" @confirm="confirm"></u-picker>
<view class="u-demo-result-line">{{ input ? input : 'Picker值' }}</view>
<u-picker
:mode="mode"
:defaultTime="defaultTime"
v-model="show"
:defaultRegion="defaultRegion"
:params="params"
@confirm="confirm"
:defaultSelector="defaultSelector"
:range="range"
:range-key="rangKey"
@columnchange="columnchange"
></u-picker>
</view>
</view>
<view class="u-config-wrap">
<view class="u-config-title u-border-bottom">
参数配置
</view>
<view class="u-config-title u-border-bottom">参数配置</view>
<view class="u-config-item">
<view class="u-item-title">Picker开关</view>
<u-subsection vibrateShort :current="status" :list="['显示', '隐藏']" @change="statusChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">模式选择</view>
<u-subsection vibrateShort :list="['时间', '地区']" @change="modeChange"></u-subsection>
<u-subsection vibrateShort :list="['单列', '多列', '时间', '地区']" @change="modeChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">默认时间</view>
......@@ -39,92 +45,153 @@
</template>
<script>
export default {
data() {
return {
show: false,
input: '',
mode: 'time',
defaultTime: '2019-12-11 20:15:35',
defaultRegion: ['广东省', '深圳市', '宝安区'],
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
province: true,
city: true,
area: true
}
export default {
data() {
return {
show: false,
input: '',
rangKey: 'name',
mode: 'selector',
range: ['', '', '', '', '', '', ''],
defaultTime: '2019-12-11 20:15:35',
defaultSelector: [0],
defaultRegion: ['广东省', '深圳市', '宝安区'],
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true,
province: true,
city: true,
area: true
}
};
},
computed: {
status() {
return this.show == true ? 0 : 1;
}
},
methods: {
statusChange(index) {
this.show = index == 0 ? true : false;
},
computed: {
status() {
return this.show == true ? 0 : 1;
modeChange(index) {
this.mode = ['selector', 'multiSelector', 'time', 'region'][index];
if (this.mode == 'selector') {
this.range = ['', '', '', '', '', '', ''];
this.defaultSelector = [0];
}
if (this.mode == 'multiSelector') {
this.range = [['亚洲', '欧洲'], ['中国', '日本'], ['北京', '上海', '广州']];
this.defaultSelector = [0, 0, 0];
}
this.show = true;
},
defaultTimeChange(index) {
this.defaultTime = index == 0 ? '2019-12-11 20:15:35' : '2020-02-05 13:09:42';
this.mode = 'time';
this.show = true;
},
methods: {
statusChange(index) {
this.show = index == 0 ? true : false;
},
modeChange(index) {
this.mode = index == 0 ? 'time' : 'region';
this.show = true;
},
defaultTimeChange(index) {
this.defaultTime = index == 0 ? '2019-12-11 20:15:35' : '2020-02-05 13:09:42';
this.mode = 'time';
this.show = true;
},
defaultRegionChange(index) {
this.defaultRegion = index == 0 ? ['广东省', '深圳市', '宝安区'] : ['海南省','三亚市', '海棠区'];
this.mode = 'region';
this.show = true;
},
minSecChange(index) {
if(index == 0) {
this.params.hour = true;
this.params.minute = true;
this.params.second = true;
}
if(index == 1) {
this.params.hour = false;
this.params.minute = false;
this.params.second = false;
}
this.mode = 'time';
this.show = true;
},
confirm(e) {
this.input = '';
if(this.mode == 'time') {
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.minute) this.input += ':' + e.minute;
if(this.params.second) this.input += ':' + e.second;
} else {
this.input = e.province.label + '-' + e.city.label + '-' + e.area.label;
}
defaultRegionChange(index) {
this.defaultRegion = index == 0 ? ['广东省', '深圳市', '宝安区'] : ['海南省', '三亚市', '海棠区'];
this.mode = 'region';
this.show = true;
},
minSecChange(index) {
if (index == 0) {
this.params.hour = true;
this.params.minute = true;
this.params.second = true;
}
if (index == 1) {
this.params.hour = false;
this.params.minute = false;
this.params.second = false;
}
this.mode = 'time';
this.show = true;
},
confirm(e) {
this.input = '';
if (this.mode == 'time') {
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.minute) this.input += ':' + e.minute;
if (this.params.second) this.input += ':' + e.second;
} else if (this.mode == 'region') {
this.input = e.province.label + '-' + e.city.label + '-' + e.area.label;
} else if (this.mode == 'selector') {
this.input = this.range[e[0]];
} else if (this.mode == 'multiSelector') {
this.input = this.range[0][e[0]] + '-' + this.range[1][e[1]] + '-' + this.range[2][e[2]];
}
},
columnchange(e) {
let column = e.column, index = e.index;
this.defaultSelector.splice(column, 1, index)
switch (column) {
case 0:
switch (index) {
case 0:
this.range[1] = ['中国', '日本']
this.range[2] = ['北京', '上海', '广州']
break
case 1:
this.range[1] = ['英国', '法国']
this.range[2] = ['伦敦', '曼彻斯特']
break
}
this.defaultSelector.splice(1, 1, 0)
this.defaultSelector.splice(2, 1, 0)
break
case 1: //拖动第2列
switch (this.defaultSelector[0]) { //判断第一列是什么
case 0:
switch (this.defaultSelector[1]) {
case 0:
this.range[2] = ['北京', '上海', '广州']
break
case 1:
this.range[2] = ['东京','北海道']
break
}
break
case 1:
switch (this.defaultSelector[1]) {
case 0:
this.range[2] = ['伦敦', '曼彻斯特']
break
case 1:
this.range[2] = ['巴黎', '马赛']
break
}
break
}
this.defaultSelector.splice(2, 1, 0)
break
}
this.$forceUpdate()
}
}
};
</script>
<style lang="scss" scoped>
.input {
border: 1px solid $u-light-color;
border-radius: 4px;
margin-bottom: 20px;
height: 30px;
font-size: 26rpx;
flex: 1;
}
.input-wrap {
display: flex;
}
.input {
border: 1px solid $u-light-color;
border-radius: 4px;
margin-bottom: 20px;
height: 30px;
font-size: 26rpx;
flex: 1;
}
.input-wrap {
display: flex;
}
</style>
<template>
<view class="wrap">
<u-waterfall :flowList="flowList" ref="uWaterfall">
<u-waterfall v-model="flowList" ref="uWaterfall">
<template v-slot:left="{ leftList }">
<view class="demo-warter" v-for="(item, index) in leftList" :key="index">
<!-- 警告:微信小程序不支持嵌入lazyload组件,请自行如下使用image标签 -->
......
......@@ -3,7 +3,7 @@
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<u-number-box :value="value" :bg-color="bgColor" :color="color"
<u-number-box :value="value" :bg-color="bgColor" :color="color" :min="0"
:step="step" :disabled="disabled"></u-number-box>
</view>
</view>
......
......@@ -23,7 +23,7 @@
<u-subsection vibrateShort :current="current" :list="['线型', '圆型']" @change="modeChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">增减(圆型时只能增,不能减)</view>
<view class="u-item-title">增减</view>
<u-subsection vibrateShort :list="['减少30%', '增加30%']" @change="calcChange"></u-subsection>
</view>
<view class="u-config-item">
......
<template>
<view class="wrap">
<u-button @click="clear">清空列表</u-button>
<u-waterfall :flowList="flowList" ref="uWaterfall">
<template v-slot:left="{leftList}">
<view class="demo-warter" v-for="(item, index) in leftList" :key="index">
<!-- 警告:微信小程序不支持嵌入lazyload组件,请自行如下使用image标签 -->
<!-- #ifndef MP-WEIXIN -->
<u-lazy-load threshold="-450" border-radius="10" :image="item.image" :index="index"></u-lazy-load>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="demo-img-wrap">
<image class="demo-image" :src="item.image" mode="widthFix"></image>
</view>
<!-- #endif -->
<view class="demo-title">
{{item.title}}
</view>
<view class="demo-price">
{{item.price}}
</view>
<view class="demo-tag">
<view class="demo-tag-owner">
自营
</view>
<view class="demo-tag-text">
放心购
</view>
</view>
<view class="demo-shop">
{{item.shop}}
</view>
<u-icon name="close-circle-fill" color="#fa3534" size="34" class="u-close" @click="remove(item.id)"></u-icon>
</view>
</template>
<template v-slot:right="{rightList}">
<view class="demo-warter" v-for="(item, index) in rightList" :key="index">
<!-- #ifndef MP-WEIXIN -->
<u-lazy-load threshold="-450" border-radius="10" :image="item.image" :index="index"></u-lazy-load>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<view class="demo-img-wrap">
<image class="demo-image" :src="item.image" mode="widthFix"></image>
</view>
<!-- #endif -->
<view class="demo-title">
{{item.title}}
</view>
<view class="demo-price">
{{item.price}}
</view>
<view class="demo-tag">
<view class="demo-tag-owner">
自营
</view>
<view class="demo-tag-text">
放心购
</view>
</view>
<view class="demo-shop">
{{item.shop}}
</view>
<u-icon name="close-circle-fill" color="#fa3534" size="34" class="u-close" @click="remove(item.id)"></u-icon>
</view>
</template>
</u-waterfall>
<u-loadmore bg-color="rgb(240, 240, 240)" :status="loadStatus" @loadmore="addRandomData"></u-loadmore>
<view class="">
<u-keyboard ref="uKeyboard" mode="number" v-model="show" @backspace="backspace" @change="change"><u-message-input :value="value"></u-message-input></u-keyboard>
</view>
</template>
<script>
export default {
data() {
return {
loadStatus: 'loadmore',
flowList: [],
list: [
{
price: 35,
title: '北国风光,千里冰封,万里雪飘',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic.sc.chinaz.com/Files/pic/pic9/202002/zzpic23327_s.jpg',
},
{
price: 75,
title: '望长城内外,惟余莽莽',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic.sc.chinaz.com/Files/pic/pic9/202002/zzpic23325_s.jpg',
},
{
price: 385,
title: '大河上下,顿失滔滔',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic2.sc.chinaz.com/Files/pic/pic9/202002/hpic2119_s.jpg',
},
{
price: 784,
title: '欲与天公试比高',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic2.sc.chinaz.com/Files/pic/pic9/202002/zzpic23369_s.jpg',
},
{
price: 7891,
title: '须晴日,看红装素裹,分外妖娆',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic2.sc.chinaz.com/Files/pic/pic9/202002/hpic2130_s.jpg',
},
{
price: 2341,
shop: '李白杜甫白居易旗舰店',
title: '江山如此多娇,引无数英雄竞折腰',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg',
},
{
price: 661,
shop: '李白杜甫白居易旗舰店',
title: '惜秦皇汉武,略输文采',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23344_s.jpg',
},
{
price: 1654,
title: '唐宗宋祖,稍逊风骚',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23343_s.jpg',
},
{
price: 1678,
title: '一代天骄,成吉思汗',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23343_s.jpg',
},
{
price: 924,
title: '只识弯弓射大雕',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23343_s.jpg',
},
{
price: 8243,
title: '俱往矣,数风流人物,还看今朝',
shop: '李白杜甫白居易旗舰店',
image: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23343_s.jpg',
},
]
}
export default {
data() {
return {
show: true,
value: ''
};
},
methods: {
change(val) {
this.value += val;
},
onLoad() {
this.addRandomData();
},
onReachBottom() {
this.loadStatus = 'loading';
// 模拟数据加载
setTimeout(() => {
this.addRandomData();
this.loadStatus = 'loadmore';
}, 1000)
},
methods: {
addRandomData() {
for(let i = 0; i < 10; i++) {
let index = this.$u.random(0, this.list.length - 1);
// 先转成字符串再转成对象,避免数组对象引用导致数据混乱
let item = JSON.parse(JSON.stringify(this.list[index]))
item.id = this.$u.guid();
this.flowList.push(item);
}
},
remove(id) {
this.$refs.uWaterfall.remove(id);
},
clear() {
this.$refs.uWaterfall.clear();
}
backspace() {
// 删除value的最后一个字符
if (this.value.length) this.value = this.value.substr(0, this.value.length - 1);
//console.log(this.value);
}
}
};
</script>
<style>
/* page不能写带scope的style标签中,否则无效 */
page {
background-color: rgb(240, 240, 240);
}
</style>
<style lang="scss" scoped>
.demo-warter {
border-radius: 8px;
margin: 5px;
background-color: #ffffff;
padding: 8px;
position: relative;
}
.u-close {
position: absolute;
top: 32rpx;
right: 32rpx;
}
.demo-image {
width: 100%;
border-radius: 4px;
}
.demo-title {
font-size: 30rpx;
margin-top: 5px;
color: $u-main-color;
}
.demo-tag {
display: flex;
margin-top: 5px;
}
.demo-tag-owner {
background-color: $u-type-error;
color: #FFFFFF;
display: flex;
align-items: center;
padding: 4rpx 14rpx;
border-radius: 50rpx;
font-size: 20rpx;
line-height: 1;
}
.demo-tag-text {
border: 1px solid $u-type-primary;
color: $u-type-primary;
margin-left: 10px;
border-radius: 50rpx;
line-height: 1;
padding: 4rpx 14rpx;
display: flex;
align-items: center;
border-radius: 50rpx;
font-size: 20rpx;
}
.demo-price {
font-size: 30rpx;
color: $u-type-error;
margin-top: 5px;
}
.demo-shop {
font-size: 22rpx;
color: $u-tips-color;
margin-top: 5px;
}
</style>
\ No newline at end of file
......@@ -9,7 +9,7 @@
<%= htmlWebpackPlugin.options.title %>
</title>
<!-- 正式发布的时候使用,开发期间不启用。↓ -->
<script src="<%= BASE_URL %>/static/common/js/touch-emulator.js"></script>
<script src="/static/common/js/touch-emulator.js"></script>
<script>
TouchEmulator();
</script>
......
......@@ -24,7 +24,12 @@
></canvas>
</view>
<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
<!-- #ifdef H5 -->
<view class="upload" @tap="uploadTap">选择图片</view>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="upload" @tap="uploadTap">重新选择</view>
<!-- #endif -->
<view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
</view>
</view>
......
......@@ -23,27 +23,6 @@
</template>
<script>
/**
* carKeyboard 车牌号键盘
* @description 此为uViw自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3中模式,都有可以打乱按键顺序的选项。
* @tutorial https://www.uviewui.com/components/keyboard.html
* @property {String} mode 键盘类型,见官网基本使用的说明(默认number)
* @property {Boolean} dot-enabled 是否显示"."按键,只在mode=number时有效(默认true)
* @property {Boolean} tooltip 是否显示键盘顶部工具条(默认true)
* @property {String} tips 工具条中间的提示文字,见官网基本使用的说明,如不需要,请传""空字符
* @property {Boolean} cancel-btn 是否显示工具条左边的"取消"按钮(默认true)
* @property {Boolean} confirm-btn 是否显示工具条右边的"完成"按钮(默认true)
* @property {Boolean} mask 是否显示遮罩(默认true)
* @property {Number String} z-index 弹出键盘的z-index值(默认1075)
* @property {Boolean} random 是否打乱键盘按键的顺序(默认false)
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
* @property {Boolean} mask-close-able 是否允许点击遮罩收起键盘(默认true)
* @event {Function} change 按键被点击(不包含退格键被点击)
* @event {Function} cancel 键盘顶部工具条左边的"取消"按钮被点击
* @event {Function} confirm 键盘顶部工具条右边的"完成"按钮被点击
* @event {Function} backspace 键盘退格键被点击
* @example <u-keyboard ref="uKeyboard" mode="car" v-model="show"></u-keyboard>
*/
export default {
name: "u-keyboard",
props: {
......
......@@ -76,33 +76,34 @@
// 整个圆环进度区域的背景色
bgColor: {
type: String,
default: "#ffffff"
default: "#ffffff"
}
},
data() {
return {
elBgId: this.$u.guid(),
elId: this.$u.guid(),
ctxBg: '', // 背景canvas实例
ctx: '', // 前景(激活时候)canvas的实例
count: 0, // 计数器
timer: null, // 定时器
times: 0, // 总共要执行的动画次数,setInterval的次数
time: 0, // 执行整个动画的时间
elBgId: 'uCircleProgressBgId', // 微信小程序中不能使用this.$u.guid()形式动态生成id值,否则会报错
elId: 'uCircleProgressElId',
widthPx: uni.upx2px(this.width), // 转成px后的整个组件的背景宽度
borderWidthPx: uni.upx2px(this.borderWidth), // 转成px后的圆环的宽度
mode: 'more', // more-percent增加,less-percent减少
startAngle: -Math.PI / 2, // canvas画圆的起始角度,默认为3点钟方向,定位到12点钟方向
progressContext: null, // 活动圆的canvas上下文
newPercent: 0, // 当动态修改进度值的时候,保存进度值的变化前后值,用于比较用
oldPercent: 0, // 当动态修改进度值的时候,保存进度值的变化前后值,用于比较用
}
},
watch: {
percent: {
immediate: true,
handler(nVal, oVal = 0) {
this.mode = nVal > oVal ? 'more' : 'less';
this.times = Math.ceil(nVal * 3.6);
this.time = Math.ceil(this.duration / 360 * this.times);
if(nVal > 100) nVal = 100;
if(nVal < 0) oVal = 0;
// 此值其实等于this.percent,命名一个新
this.newPercent = nVal;
this.oldPercent = oVal;
setTimeout(() => {
this.countInterval();
// 无论是百分比值增加还是减少,需要操作还是原来的旧的百分比值
// 将此值减少或者新增到新的百分比值
this.drawCircleByProgress(oVal);
}, 50)
}
}
......@@ -115,53 +116,63 @@
}
},
mounted() {
this.ctxBg = uni.createCanvasContext(this.elBgId, this);
this.ctx = uni.createCanvasContext(this.elId, this);
// 在h5端,必须要做一点延时才起作用,this.$nextTick()无效(HX2.4.7)
setTimeout(() => {
this.drawProgressBg();
this.drawCircleByProgress(0);
}, 50)
},
methods: {
drawProgressBg() {
this.ctxBg.setLineWidth(this.borderWidthPx); // 设置圆环宽度
this.ctxBg.setStrokeStyle(this.inactiveColor); // 线条颜色
this.ctxBg.setLineCap('round'); // 圆环端点的形状为圆形
this.ctxBg.beginPath(); // 开始描绘路径
let ctx = uni.createCanvasContext(this.elBgId, this);
ctx.setLineWidth(this.borderWidthPx); // 设置圆环宽度
ctx.setStrokeStyle(this.inactiveColor); // 线条颜色
ctx.beginPath(); // 开始描绘路径
// 设置一个原点(110,110),半径为100的圆的路径到当前路径
this.ctxBg.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, 0, 2 * Math.PI,
false);
this.ctxBg.stroke(); // 对路径进行描绘
this.ctxBg.draw();
let radius = this.widthPx / 2;
ctx.arc(radius, radius, radius - this.borderWidthPx, 0, 2 * Math.PI,false);
ctx.stroke(); // 对路径进行描绘
ctx.draw();
},
drawCircle(step) {
this.ctx.setLineWidth(this.borderWidthPx);
this.ctx.setStrokeStyle(this.circleColor);
this.ctx.setLineCap('round');
this.ctx.beginPath();
// 参数step 为绘制的圆环周长,从0到2为一周 。 -Math.PI / 2 将起始角设在12点钟位置 ,结束角 通过改变 step 的值确定
if (this.mode == 'more') {
this.ctx.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, -Math.PI / 2, step *
Math.PI - Math.PI / 2, false);
drawCircleByProgress(progress) {
// 第一次操作进度环时将上下文保存到了this.data中,直接使用即可
let ctx = this.progressContext;
if (!ctx) {
ctx = uni.createCanvasContext(this.elId, this);
this.progressContext = ctx;
}
// 表示进度的两端为圆形
ctx.setLineCap('round');
// 设置线条的宽度和颜色
ctx.setLineWidth(this.borderWidthPx);
ctx.setStrokeStyle(this.circleColor);
// 将总过渡时间除以100,得出每修改百分之一进度所需的时间
let time = Math.floor(this.duration / 100);
// 结束角的计算依据为:将2π分为100份,乘以当前的进度值,得出终止点的弧度值,加起始角,为整个圆从默认的
// 3点钟方向开始画图,转为更好理解的12点钟方向开始作图,这需要起始角和终止角同时加上this.startAngle值
let endAngle = ((2 * Math.PI) / 100) * progress + this.startAngle;
ctx.beginPath();
// 半径为整个canvas宽度的一半
let radius = this.widthPx / 2;
ctx.arc(radius, radius, radius - this.borderWidthPx, this.startAngle, endAngle, false);
ctx.stroke();
ctx.draw();
// 如果变更后新值大于旧值,意味着增大了百分比
if(this.newPercent > this.oldPercent) {
// 每次递增百分之一
progress ++;
// 如果新增后的值,大于需要设置的值百分比值,停止继续增加
if (progress > this.newPercent) return;
} else {
this.ctx.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, -Math.PI / 2, Math
.PI / 2 - step *
Math.PI, false);
// 同理于上面
progress --;
if (progress < this.newPercent) return ;
}
this.ctx.stroke();
this.ctx.draw()
},
countInterval() {
this.countTimer = setInterval(() => {
if (this.count <= this.times) {
// 全一个圆时候,值为2,这里求出每一份的值为2/360
this.drawCircle(this.count * 2 / 360);
this.count++;
} else {
clearInterval(this.countTimer);
}
}, Math.ceil(this.duration / 360)); // 总过渡时间分为360份,这里为每一份的时间
},
setTimeout(() => {
// 定时器,每次操作间隔为time值,为了让进度条有动画效果
this.drawCircleByProgress(progress);
}, time);
}
}
}
</script>
......
......@@ -129,6 +129,7 @@
},
// 键盘关闭
popupClose() {
console.log(333);
// 通过发送input这个特殊的事件名,可以修改父组件传给props的value的变量,也即双向绑定
this.$emit('input', false);
},
......
......@@ -88,12 +88,10 @@
right: 0;
bottom: 0;
opacity: 0;
visibility: hidden;
}
.u-mask-show {
opacity: 1;
visibility: visible;
transform: scale(1);
}
</style>
<template>
<view class="u-char-box">
<view class="u-char-flex">
<input :value="valueModel" type="number" :focus="focus" :maxlength="maxlength" class="u-input" @input="getVal" />
<input :disabled="disabledKeyboard" :value="valueModel" type="number" :focus="focus" :maxlength="maxlength" class="u-input" @input="getVal"/>
<view v-for="(item, index) in maxlength" :key="index">
<view :class="[breathe && charArrLength == index ? 'u-breathe' : '', 'u-char-item',
charArrLength === index && mode == 'box' ? 'u-box-active' : '',
......@@ -48,6 +48,7 @@
* @property {String} active-color 当前激活输入框的样式(默认#2979ff)
* @property {String} focus 非激活输入框的样式,文字颜色同此值(默认#606266)
* @property {String | Number} width 输入框宽度,单位rpx,高等于宽(默认80)
* @property {Boolean} disabled-keyboard 禁止点击输入框唤起系统键盘(默认false)
* @event {Function} change 输入内容发生改变时触发,具体见官网说明
* @event {Function} finish 输入字符个数达maxlength值时触发,见官网说明
* @example <u-message-input mode="bottomLine"></u-message-input>
......@@ -109,6 +110,11 @@
width: {
type: [Number, String],
default: '80'
},
// 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
disabledKeyboard: {
type: Boolean,
default: false
}
},
watch: {
......@@ -197,12 +203,12 @@
.u-input {
position: absolute;
top: 0;
left: -100%;
width: 200%;
left: 0;
width: 100%;
height: 100%;
text-align: left;
z-index: 9;
opacity: 1;
opacity: 0;
background: none;
}
......
......@@ -76,8 +76,8 @@
* @example <u-modal :src="title" :content="content"></u-modal>
*/
export default {
name: 'u-modal',
props: {
name: 'u-modal',
// 是否显示Modal
value: {
type: Boolean,
......
......@@ -12,7 +12,12 @@
</view>
</view>
<view class="u-navbar-content-title" v-if="title" :style="[titleStyle]">
<view class="u-title u-line-1">{{title}}</view>
<view class="u-title u-line-1" :style="{
color: titleColor,
fontSize: titleSize + 'rpx'
}">
{{title}}
</view>
</view>
<view class="u-slot-content">
<slot></slot>
......@@ -173,8 +178,6 @@ export default {
// 导航中间的标题的样式
titleStyle() {
let style = {};
style.color = this.titleColor;
style.fontSize = this.titleSize + 'rpx';
// #ifndef MP
style.left = (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + 'px';
style.right = (systemInfo.windowWidth - uni.upx2px(this.titleWidth)) / 2 + 'px';
......
<template>
<view class="u-numberbox">
<view class="u-icon-minus" @tap="minus" :class="{ 'u-icon-disabled': disabled || inputVal <= min }" :style="{
<view class="u-icon-minus" @tap.stop="minus" :class="{ 'u-icon-disabled': disabled || inputVal <= min }" :style="{
background: bgColor,
height: inputHeight + 'rpx',
color: color
}">
<u-icon name="minus" :size="size"></u-icon>
</view>
<input :disabled="disabledInput || disabled" :class="{ 'u-input-disabled': disabled }" v-model="inputVal" class="u-number-input" @blur="onBlur"
<input :disabled="disabledInput || disabled" :cursor-spacing="getCursorSpacing" :class="{ 'u-input-disabled': disabled }" v-model="inputVal" class="u-number-input" @blur="onBlur"
type="number" :style="{
color: color,
fontSize: size + 'rpx',
......@@ -15,7 +15,7 @@
height: inputHeight + 'rpx',
width: inputWidth + 'rpx'
}" />
<view class="u-icon-plus" @tap="plus" :class="{ 'u-icon-disabled': disabled || inputVal >= max }" :style="{
<view class="u-icon-plus" @tap.stop="plus" :class="{ 'u-icon-disabled': disabled || inputVal >= max }" :style="{
background: bgColor,
height: inputHeight + 'rpx',
color: color
......@@ -37,11 +37,12 @@
* @property {Number} step 步长,每次加或减的值(默认1)
* @property {Boolean} disabled 是否禁用操作,禁用后无法加减或手动修改输入框的值(默认false)
* @property {Boolean} disabled-input 是否禁止输入框手动输入值(默认false)
* @property {String Number} size 输入框文字和按钮字体大小,单位rpx(默认26)
* @property {String | Number} size 输入框文字和按钮字体大小,单位rpx(默认26)
* @property {String} color 输入框文字和加减按钮图标的颜色(默认#323233)
* @property {String Number} input-width 输入框宽度,单位rpx(默认80)
* @property {String Number} input-height 输入框和按钮的高度,单位rpx(默认50)
* @property {String Number} index 事件回调时用以区分当前发生变化的是哪个输入框
* @property {String | Number} input-width 输入框宽度,单位rpx(默认80)
* @property {String | Number} input-height 输入框和按钮的高度,单位rpx(默认50)
* @property {String | Number} index 事件回调时用以区分当前发生变化的是哪个输入框
* @property {String | Number} cursor-spacing 指定光标于键盘的距离,避免键盘遮挡输入框,单位rpx(默认200)
* @event {Function} change 输入框内容发生变化时触发,对象形式
* @event {Function} blur 输入框失去焦点时触发,对象形式
* @event {Function} minus 点击减少按钮时触发(按钮可点击情况下),对象形式
......@@ -111,6 +112,11 @@
disabledInput: {
type: Boolean,
default: false
},
// 输入框于键盘之间的距离
cursorSpacing: {
type: [Number, String],
default: 100
}
},
watch: {
......@@ -121,8 +127,8 @@
// 为了让用户能够删除所有输入值,重新输入内容,删除所有值后,内容为空字符串
if (v1 == '') return;
let value = 0;
// 首先判断是否正整数,并且第一位数字不为0,并且在min和max之间,如果不是,使用原来值
let tmp = /(^\d+$)/.test(v1) && String(v1)[0] != 0;
// 首先判断是否正整数,并且在min和max之间,如果不是,使用原来值
let tmp = /(^\d+$)/.test(v1);
if (tmp && v1 >= this.min && v1 <= this.max) value = v1;
else value = v2;
this.handleChange(value, 'change');
......@@ -139,6 +145,12 @@
created() {
this.inputVal = +this.value;
},
computed: {
getCursorSpacing() {
// 先将值转为px单位,再转为数值
return Number(uni.upx2px(this.cursorSpacing));
}
},
methods: {
minus() {
this.computeVal('minus');
......
......@@ -32,7 +32,7 @@
</view>
</picker-view-column>
</picker-view>
<picker-view v-else :value="valueArr" @change="change" class="u-picker-view">
<picker-view v-else-if="mode == 'time'" :value="valueArr" @change="change" class="u-picker-view">
<picker-view-column v-if="!reset && params.year">
<view class="u-column-item" v-for="(item,index) in years" :key="index">
{{ item }}<text class="u-text" v-if="showTimeTag"></text>
......@@ -64,6 +64,24 @@
</view>
</picker-view-column>
</picker-view>
<picker-view v-else-if="mode == 'selector'" :value="defaultSelector" @change="change" class="u-picker-view">
<picker-view-column>
<view class="u-column-item" v-for="(item,index) in range" :key="index">
<view class="u-line-1">
{{getItemValue(item)}}
</view>
</view>
</picker-view-column>
</picker-view>
<picker-view v-else-if="mode == 'multiSelector'" :value="defaultSelector" @change="change" class="u-picker-view">
<picker-view-column v-for="(item,index) in range" :key="index">
<view class="u-column-item" v-for="(item1,index1) in item" :key="index1">
<view class="u-line-1">
{{getItemValue(item1)}}
</view>
</view>
</picker-view-column>
</picker-view>
</view>
</view>
</u-popup>
......@@ -91,6 +109,9 @@
* @property {String} default-code 默认选中的地区,编号形式,mode=region时有效
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
* @property {String Number} z-index 弹出时的z-index值(默认1075)
* @property {Array} default-selector 数组形式,其中每一项表示选择了range对应项中的第几个
* @property {Array} range 自定义选择的数据,mode=selector或mode=multiSelector时有效
* @property {String} range-key 当range参数的元素为对象时,指定Object中的哪个key的值作为选择器显示内容
* @event {Function} confirm 点击确定按钮,返回当前选择的值
* @event {Function} cancel 点击取消按钮,返回当前选择的值
* @example <u-picker v-model="show" mode="time"></u-picker>
......@@ -115,7 +136,26 @@
}
}
},
// 模式选择,region-地区类型,time-时间类型
// 当mode=selector或者mode=multiSelector时,提供的数组
range: {
type: Array,
default() {
return []
}
},
// 当mode=selector或者mode=multiSelector时,提供的默认选中的下标
defaultSelector: {
type: Array,
default() {
return [0]
}
},
// 当 range 是一个 Array<Object> 时,通过 range-key 来指定 Object 中 key 的值作为选择器显示内容
rangeKey: {
type: String,
default: ''
},
// 模式选择,region-地区类型,time-时间类型,selector-单列模式,multiSelector-多列模式
mode: {
type: String,
default: 'time'
......@@ -207,7 +247,8 @@
areas: areas[0][0],
province: 0,
city: 0,
area: 0
area: 0,
multiSelectorValue: [], // 多列时,保存上一次的列选择,用于对下一次变更时,对比是哪一列发生了变化
}
},
mounted() {
......@@ -245,17 +286,19 @@
yearAndMonth(val) {
if (this.params.year) this.setDays();
},
// 微信和QQ小程序由于一些奇怪的原因,需要重新初始化才能显示正确的值
// 微信和QQ小程序由于一些奇怪的原因(故同时对所有平台均初始化一遍),需要重新初始化才能显示正确的值
value(n) {
if (n) {
// #ifdef MP-WEIXIN || MP-QQ
this.reset = true;
setTimeout(() => this.init(), 10);
// #endif
}
}
},
methods: {
// 对单列和多列形式的判断是否有传入变量的情况
getItemValue(item) {
return typeof item == 'object' ? item[this.rangeKey] : item
},
// 小于10前面补0,用于月份,日期,时分秒等
formatNumber(num) {
return +num < 10 ? '0' + num : String(num);
......@@ -318,7 +361,7 @@
this.valueArr.push(0);
this.setSeconds();
}
} else {
} else if(this.mode == 'region') {
if (this.params.province) {
this.valueArr.push(0);
this.setProvinces();
......@@ -331,6 +374,11 @@
this.valueArr.push(0);
this.setAreas();
}
} else if(this.mode == 'selector') {
this.valueArr = this.defaultSelector;
} else if(this.mode == 'multiSelector') {
this.valueArr = this.defaultSelector;
this.multiSelectorValue = this.defaultSelector;
}
this.$forceUpdate();
},
......@@ -443,11 +491,25 @@
if (this.params.hour) this.hour = this.hours[this.valueArr[i++]];
if (this.params.minute) this.minute = this.minutes[this.valueArr[i++]];
if (this.params.second) this.second = this.seconds[this.valueArr[i++]];
} else {
} else if(this.mode == 'region') {
if (this.params.province) this.province = this.valueArr[i++];
if (this.params.city) this.city = this.valueArr[i++];
if (this.params.area) this.area = this.valueArr[i++];
}
} else if(this.mode == 'multiSelector') {
let index = 0;
// 对比前后两个数组,寻找变更的是哪一列,如果某一个元素不同,即可判定该列发生了变化
this.multiSelectorValue.map((val, idx) => {
if(val != this.valueArr[idx]) index = idx;
})
// 保存当前最新的数组,便于下次进行对比
// this.multiSelectorValue = e.detail.value;
// 模仿uniapp的picker组件为multiSelector模式时,对外抛出的参数,保持一致,同时也是为了让用户对多列
// 变化时,对动态设置其他列的变更
this.$emit('columnchange', {
column: index,
index: this.valueArr[index]
})
}
},
// 用户点击确定按钮
getResult(event = null) {
......@@ -460,10 +522,14 @@
if (this.params.hour) result.hour = this.formatNumber(this.hour || 0);
if (this.params.minute) result.minute = this.formatNumber(this.minute || 0);
if (this.params.second) result.second = this.formatNumber(this.second || 0);
} else {
} else if (this.mode == 'region') {
if (this.params.province) result.province = provinces[this.province];
if (this.params.city) result.city = citys[this.province][this.city];
if (this.params.area) result.area = areas[this.province][this.city][this.area];
} else if (this.mode == 'selector') {
result = this.valueArr;
} else if (this.mode == 'multiSelector') {
result = this.valueArr;
}
if (event) this.$emit(event, result);
this.close();
......
......@@ -15,11 +15,27 @@
:style="[style]"
>
<view class="u-mode-center-box" @tap.stop.prevent @touchmove.stop.prevent v-if="mode == 'center'" :style="[centerStyle]">
<u-icon @click="close" v-if="closeable" class="u-close" :class="['u-close--' + closeIconPos]" :name="closeIcon" :color="closeIconColor" :size="closeIconSize"></u-icon>
<u-icon
@click="close"
v-if="closeable"
class="u-close"
:class="['u-close--' + closeIconPos]"
:name="closeIcon"
:color="closeIconColor"
:size="closeIconSize"
></u-icon>
<slot />
</view>
<block v-else><slot /></block>
<u-icon v-if="mode != 'center' && closeable" @click="close" class="u-close" :class="['u-close--' + closeIconPos]" :name="closeIcon" :color="closeIconColor" :size="closeIconSize"></u-icon>
<u-icon
v-if="mode != 'center' && closeable"
@click="close"
class="u-close"
:class="['u-close--' + closeIconPos]"
:name="closeIcon"
:color="closeIconColor"
:size="closeIconSize"
></u-icon>
</view>
</view>
</template>
......@@ -247,14 +263,13 @@ export default {
// 此处的原理是,关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件
// 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用
change(param1, param2, status) {
// 如果this.popup为false,以为着为picker,actionsheet等组件调用了popup组件
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
if (this.popup == true) this.$emit('input', status);
this[param1] = status;
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(
() => {
this.timer = setTimeout(() => {
this[param2] = status;
this.$emit(status ? 'open' : 'close');
},
......
......@@ -21,7 +21,7 @@
animationPlayState: animationPlayState,
}"
>
<text class="u-notice-text" @tap="click(index)" :style="{
<text class="u-notice-text" @tap="click" :style="{
fontSize: fontSize + 'rpx',
}">{{showText}}</text>
</view>
......@@ -185,7 +185,7 @@ export default {
},
// 点击通告栏
click(index) {
this.$emit('click', index);
this.$emit('click');
},
// 点击关闭按钮
close() {
......
......@@ -65,8 +65,9 @@
* @property {String} margin 组件与其他上下左右元素之间的距离,带单位的字符串形式,如"30rpx"
* @property {Boolean} animation 是否开启动画,见上方说明(默认false)
* @property {String} value 输入框初始值
* @property {String | Number} maxlength 输入框最大能输入的长度,-1为不限制长度
* @property {Boolean} input-style input输入框的样式,可以定义文字颜色,大小等,对象形式
* @property {String Number} height 输入框高度,单位rpx(默认64)
* @property {String | Number} height 输入框高度,单位rpx(默认64)
* @event {Function} change 输入框内容发生变化时触发
* @event {Function} search 用户确定搜索时触发,用户按回车键,或者手机键盘右下角的"搜索"键时触发
* @event {Function} custom 用户点击右侧控件时触发
......
......@@ -166,6 +166,8 @@ export default {
// 否则造成通信阻塞,需要每改变一个step值时修改一次视图
this.newValue = (this.distanceX / this.sliderRect.width) * 100;
this.status = 'moving';
// 发出moving事件
this.$emit('moving');
this.updateValue(this.newValue, true);
},
onTouchEnd() {
......
......@@ -12,13 +12,13 @@
width: movableViewWidth
}"
>
<view class="u-swipe-content" @tap.stop="contentClick"><slot></slot></view>
<view
class="u-swipe-del"
@tap.stop="btnClick(index)"
:style="[btnStyle(item.style)]"
v-for="(item, index) in options" :key="index"
class="u-swipe-content"
@tap.stop="contentClick"
>
<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-btn-text">{{ item.text }}</view>
</view>
</movable-view>
......@@ -115,11 +115,11 @@ export default {
return uni.upx2px(this.btnWidth) * this.options.length;
},
btnStyle() {
return (style) => {
return style => {
let css = {};
style.width = this.btnWidth + 'rpx';
return style;
}
};
}
},
mounted() {
......@@ -202,7 +202,7 @@ export default {
// 点击内容触发事件
contentClick() {
// 点击内容时,如果当前为打开状态,收起组件
if(this.status == true) {
if (this.status == true) {
this.status = 'close';
this.moveX = 0;
}
......
......@@ -56,7 +56,7 @@
},
// 当前活动tab的索引
current: {
type: Number,
type: [Number, String],
default: 0
},
// 导航栏的高度和行高
......@@ -143,12 +143,15 @@
parentLeft: 0, // 父元素(tabs组件)到屏幕左边的距离
id: this.$u.guid(), // id值
currentIndex: this.current,
barFirstTimeMove: true, // 滑块第一次移动时(页面刚生成时),无需动画,否则给人怪异的感觉
};
},
watch: {
// 监听tab的变化,重新计算tab菜单的布局信息,因为实际使用中菜单可能是通过
// 后台获取的(如新闻app顶部的菜单),获取返回需要一定时间,所以list变化时,重新获取布局信息
list(n, o) {
// list变动时,重制内部索引,否则可能导致超出数组边界的情况
this.currentIndex = 0;
// 用$nextTick等待视图更新完毕后再计算tab的局部信息,否则可能因为tab还没生成就获取,就会有问题
this.$nextTick(() => {
this.init();
......@@ -156,7 +159,7 @@
},
current: {
immediate: true,
handler(nVal) {
handler(nVal, oVal) {
// 视图更新后再执行移动操作
this.$nextTick(() => {
this.currentIndex = nVal;
......@@ -171,7 +174,8 @@
let style = {
width: this.barWidth + 'rpx',
transform: `translate(${this.scrollBarLeft}px, -100%)`,
'transition-duration': `${this.duration}s`,
// 滑块在页面渲染后第一次滑动时,无需动画效果
'transition-duration': `${this.barFirstTimeMove ? 0 : this.duration }s`,
'background-color': this.activeColor,
height: this.barHeight + 'rpx',
// 设置一个很大的值,它会自动取能用的最大值,不用高度的一半,是因为高度可能是单数,会有小数出现
......@@ -217,6 +221,8 @@
},
// 点击某一个tab菜单
clickTab(index) {
// 点击当前活动tab,不触发事件
if(index == this.currentIndex) return ;
// 发送事件给父组件
this.$emit('change', index);
},
......@@ -257,6 +263,13 @@
let left = tabInfo.left + tabInfo.width / 2 - this.parentLeft;
// 计算当前活跃item到组件左边的距离
this.scrollBarLeft = left - uni.upx2px(this.barWidth) / 2;
// 第一次移动滑块的时候,barFirstTimeMove为true,放到延时中将其设置false
// 延时是因为scrollBarLeft作用于computed计算时,需要一个过程需,否则导致出错
if(this.barFirstTimeMove == true) {
setTimeout(() => {
this.barFirstTimeMove = false;
}, 100)
}
}
},
mounted() {
......
......@@ -115,7 +115,7 @@
// tag的背景颜色(如果有此值,会覆盖type值的颜色)
if(this.bgColor) style.backgroundColor = this.bgColor+"!important";
// 如果是镂空型tag,没有传递边框颜色(borderColor)的话,使用文字的颜色(color属性)
if(this.plain && this.color && !this.borderColor) style.borderColor = this.color;
if(this.mode == 'plain' && this.color && !this.borderColor) style.borderColor = this.color;
else style.borderColor = this.borderColor;
return style;
},
......
......@@ -17,7 +17,7 @@
export default {
name: "u-waterfall",
props: {
flowList: {
value: {
// 瀑布流数据
type: Array,
required: true,
......@@ -57,7 +57,7 @@ export default {
let startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0;
this.tempList = this.cloneData(nVal.slice(startIndex));
this.splitData();
},
}
},
mounted() {
this.tempList = this.cloneData(this.copyFlowList);
......@@ -66,7 +66,7 @@ export default {
computed: {
// 破坏flowList变量的引用,否则watch的结果新旧值是一样的
copyFlowList() {
return this.cloneData(this.flowList);
return this.cloneData(this.value);
}
},
methods: {
......@@ -109,8 +109,10 @@ export default {
clear() {
this.leftList = [];
this.rightList = [];
// 同时清除父组件列表中的数据
this.$emit('input', []);
},
// 清除某一条定的数据,根据id实现
// 清除某一条定的数据,根据id实现
remove(id) {
let tmp = false;
// 如果findIndex找不到合适的条件,就会返回-1
......@@ -124,6 +126,9 @@ export default {
index = this.rightList.findIndex(val => val[this.idKey] == id);
if(index != -1) this.rightList.splice(index, 1);
}
// 同时清除父组件的数据中的对应id的条目
index = this.value.findIndex(val => val[this.idKey] == id);
if(index != -1) this.$emit('input', this.value.splice(index, 1));
}
}
}
......
// 此版本发布于2020-05-18
let version = '1.2.7';
// 此版本发布于2020-05-22
let version = '1.2.8';
export default {
v: version,
......
{
"name": "uview-ui",
"version": "1.2.7",
"version": "1.2.8",
"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