Commit da09bd81 authored by beiqiao's avatar beiqiao

先提交一部分吧,防止电脑死机爆炸数据丢失。。。

parent 6b9cfd96
<template> <template>
<u-popup mode="bottom" :border-radius="borderRadius" <u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
:popup="false" v-model="value" :maskCloseAble="maskCloseAble" length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" <view class="u-tips u-border-bottom" v-if="tips.text" :style="tipsStyle">
@close="popupClose" {{tips.text}}
:z-index="uZIndex" </view>
> <block v-for="(item, index) in list" :key="index">
<view class="u-tips u-border-bottom" v-if="tips.text" :style="tipsStyle"> <view @touchmove.stop.prevent @tap="itemClick(index)" :style="[itemStyle(index)]" class="u-action-sheet-item" :class="[index < list.length - 1 ? 'u-border-bottom' : '']"
{{tips.text}} hover-class="u-hover-class" :hover-stay-time="150">
</view> {{item.text}}
<block v-for="(item, index) in list" :key="index"> </view>
<view @touchmove.stop.prevent @tap="itemClick(index)" :style="[itemStyle(index)]" class="u-action-sheet-item" :class="[index < list.length - 1 ? 'u-border-bottom' : '']" </block>
hover-class="u-hover-class" :hover-stay-time="150"> <view class="u-gab" v-if="cancelBtn">
{{item.text}} </view>
</view> <view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
</block> :hover-stay-time="150" v-if="cancelBtn" @tap="close">取消</view>
<view class="u-gab" v-if="cancelBtn"> </u-popup>
</view> </template>
<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class" :hover-stay-time="150" v-if="cancelBtn"
@tap="close">取消</view> <script>
</u-popup> /**
</template> * alertTips 提示
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
<script> * @tutorial https://www.uviewui.com/components/actionSheet.html
export default { * @property {Array<Object>} list 按钮的文字数组,见官方文档示例
props: { * @property {Object} tips 顶部的提示文字,见官方文档示例
// 点击遮罩是否可以关闭actionsheet * @property {Boolean} cancel-btn 是否显示底部的取消按钮(默认true)
maskCloseAble: { * @property {Number String} border-radius 弹出部分顶部左右的圆角值,单位rpx(默认0)
type: Boolean, * @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
default: true * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
}, * @property {Number String} z-index z-index值(默认1075)
// 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx * @event {Function} click 点击ActionSheet列表项时触发
list: { * @event {Function} close 点击取消按钮时触发
type: Array, * @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
default () { */
// 如下 export default {
// return [{ name: "u-action-sheet",
// text: '确定', props: {
// color: '', // 点击遮罩是否可以关闭actionsheet
// fontSize: '' maskCloseAble: {
// }] type: Boolean,
return []; default: true
} },
}, // 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx
// 顶部的提示文字 list: {
tips: { type: Array,
type: Object, default () {
default () { // 如下
return { // return [{
text: '', // text: '确定',
color: '', // color: '',
fontSize: '26' // fontSize: ''
} // }]
} return [];
}, }
// 底部的取消按钮 },
cancelBtn: { // 顶部的提示文字
type: Boolean, tips: {
default: true type: Object,
}, default () {
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距 return {
safeAreaInsetBottom: { text: '',
type: Boolean, color: '',
default: false fontSize: '26'
}, }
// 通过双向绑定控制组件的弹出与收起 }
value: { },
type: Boolean, // 底部的取消按钮
default: false cancelBtn: {
}, type: Boolean,
// 弹出的顶部圆角值 default: true
borderRadius: { },
type: [String, Number], // 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
default: 0 safeAreaInsetBottom: {
}, type: Boolean,
// 弹出的z-index值 default: false
zIndex: { },
type: [String, Number], // 通过双向绑定控制组件的弹出与收起
default: 0 value: {
} type: Boolean,
}, default: false
computed: { },
// 顶部提示的样式 // 弹出的顶部圆角值
tipsStyle() { borderRadius: {
let style = {}; type: [String, Number],
if (this.tips.color) style.color = this.tips.color; default: 0
if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx'; },
return style; // 弹出的z-index值
}, zIndex: {
// 操作项目的样式 type: [String, Number],
itemStyle() { default: 0
return (index) => { }
let style = {}; },
if (this.list[index].color) style.color = this.list[index].color; computed: {
if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx'; // 顶部提示的样式
return style; tipsStyle() {
} let style = {};
}, if (this.tips.color) style.color = this.tips.color;
uZIndex() { if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
// 如果用户有传递z-index值,优先使用 return style;
return this.zIndex ? this.zIndex : this.$u.zIndex.popup; },
} // 操作项目的样式
}, itemStyle() {
methods: { return (index) => {
// 点击取消按钮 let style = {};
close() { if (this.list[index].color) style.color = this.list[index].color;
// 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数 if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx';
// 这是一个vue发送事件的特殊用法 return style;
this.popupClose(); }
this.$emit('close'); },
}, uZIndex() {
// 弹窗关闭 // 如果用户有传递z-index值,优先使用
popupClose() { return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
this.$emit('input', false); }
}, },
// 点击某一个itemif (!this.show) return; methods: {
itemClick(index) { // 点击取消按钮
this.$emit('click', index); close() {
this.$emit('input', false); // 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
} // 这是一个vue发送事件的特殊用法
} this.popupClose();
} this.$emit('close');
</script> },
// 弹窗关闭
<style lang="scss" scoped> popupClose() {
.u-tips { this.$emit('input', false);
font-size: 26rpx; },
text-align: center; // 点击某一个itemif (!this.show) return;
padding: 34rpx 0; itemClick(index) {
line-height: 1; this.$emit('click', index);
color: $u-tips-color; this.$emit('input', false);
} }
}
.u-action-sheet-item { }
display: flex; </script>
line-height: 1;
justify-content: center; <style lang="scss" scoped>
align-items: center; .u-tips {
font-size: 34rpx; font-size: 26rpx;
padding: 34rpx 0; text-align: center;
} padding: 34rpx 0;
line-height: 1;
.u-gab { color: $u-tips-color;
height: 12rpx; }
background-color: rgb(234, 234, 236);
} .u-action-sheet-item {
display: flex;
.u-actionsheet-cancel { line-height: 1;
color: $u-main-color; justify-content: center;
} align-items: center;
font-size: 34rpx;
padding: 34rpx 0;
}
.u-gab {
height: 12rpx;
background-color: rgb(234, 234, 236);
}
.u-actionsheet-cancel {
color: $u-main-color;
}
</style> </style>
<template> <template>
<view class="u-alert-tips" v-if="show" :class="{'u-close-alert-tips': !show}" :style="{ <view class="u-alert-tips" v-if="show" :class="{'u-close-alert-tips': !show}" :style="{
backgroundColor: computeBgColor, backgroundColor: computeBgColor,
borderColor: computeBorderColor borderColor: computeBorderColor
}"> }">
<view class="u-icon-wrap"> <view class="u-icon-wrap">
<u-icon v-if="showIcon" :name="$u.type2icon(type)" :size="description ? 40 : 32" class="u-icon" :color="computeColor"></u-icon> <u-icon v-if="showIcon" :name="$u.type2icon(type)" :size="description ? 40 : 32" class="u-icon" :color="computeColor"></u-icon>
</view> </view>
<view class="u-alert-content" @tap.stop="click"> <view class="u-alert-content" @tap.stop="click">
<view class="u-alert-title" :style="{fontWeight: description ? 500 : 'normal'}"> <view class="u-alert-title" :style="{fontWeight: description ? 500 : 'normal'}">
{{title}} {{title}}
</view> </view>
<view v-if="description" class="u-alert-desc"> <view v-if="description" class="u-alert-desc">
{{description}} {{description}}
</view> </view>
</view> </view>
<view class="u-icon-wrap"> <view class="u-icon-wrap">
<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc" <u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
:size="22" class="u-close-icon" :style="{ :size="22" class="u-close-icon" :style="{
top: description ? '18rpx' : '24rpx' top: description ? '18rpx' : '24rpx'
}"></u-icon> }"></u-icon>
</view> </view>
<text v-if="closeAble && closeText" class="u-close-text" :style="{ <text v-if="closeAble && closeText" class="u-close-text" :style="{
top: description ? '18rpx' : '24rpx' top: description ? '18rpx' : '24rpx'
}">{{closeText}}</text> }">{{closeText}}</text>
</view> </view>
</template> </template>
<script> <script>
export default { /**
props: { * alertTips 提示
// 显示文字 * @description 警告提示,展现需要关注的信息。
title: { * @tutorial https://uviewui.com/components/alertTips.html
type: String, * @property {String} title 辅助性文字,颜色比title浅一点,字号也小一点,可选
default: '' * @property {String} description 显示的标题文字
}, * @property {String} type 关闭按钮(默认为叉号icon图标)
// 主题,success/warning/info/error * @property {String} close-able 用文字替代关闭图标,close-able为true时有效
type: { * @property {Boolean} show-icon 是否显示左边的辅助图标
type: String, * @property {Boolean} show 显示或隐藏组件
default: 'warning' * @event {Function} click 点击组件时触发
}, * @event {Function} close 点击关闭按钮时触发
// 辅助性文字 * @example <u-alert-tips :show="show" type="error" @close="show = false" :title="title" :close-able="true"></u-alert-tips>
description: { */
type: String, export default {
default: '' name: "u-alert-tips",
}, props: {
// 是否可关闭 // 显示文字
closeAble: { title: {
type: Boolean, type: String,
default: false default: ''
}, },
// 关闭按钮自定义文本 // 主题,success/warning/info/error
closeText: { type: {
type: String, type: String,
default: '' default: 'warning'
}, },
// 是否显示图标 // 辅助性文字
showIcon: { description: {
type: Boolean, type: String,
default: false default: ''
}, },
// 文字颜色,如果定义了color值,icon会失效 // 是否可关闭
color: { closeAble: {
type: String, type: Boolean,
default: '' default: false
}, },
// 背景颜色 // 关闭按钮自定义文本
bgColor: { closeText: {
type: String, type: String,
default: '' default: ''
}, },
// 边框颜色 // 是否显示图标
borderColor: { showIcon: {
type: String, type: Boolean,
default: '' default: false
}, },
// 是否显示 // 文字颜色,如果定义了color值,icon会失效
show: { color: {
type: Boolean, type: String,
default: true default: ''
} },
}, // 背景颜色
data() { bgColor: {
return { type: String,
} default: ''
}, },
watch: { // 边框颜色
show(val) { borderColor: {
if (val == false) { type: String,
// 先opacity隐藏,再移除 default: ''
setTimeout(() => { },
this.showAlert = false; // 是否显示
}, 300); show: {
} type: Boolean,
} default: true
}, }
computed: { },
// 计算字体颜色,如果没有自定义的,就用uview主题颜色 data() {
computeColor() { return {}
if (this.color) return this.color; },
else return this.$u.color[this.type]; watch: {
}, show(val) {
// 计算背景颜色 if (val == false) {
computeBgColor() { // 先opacity隐藏,再移除
if (this.bgColor) return this.bgColor; setTimeout(() => {
return this.$u.color[this.type + 'Light']; this.showAlert = false;
}, }, 300);
computeBorderColor() { }
if (this.borderColor) return this.borderColor; }
return this.$u.color[this.type + 'Disabled']; },
} computed: {
}, // 计算字体颜色,如果没有自定义的,就用uview主题颜色
methods: { computeColor() {
// 点击内容 if (this.color) return this.color;
click() { else return this.$u.color[this.type];
this.$emit('click'); },
}, // 计算背景颜色
// 点击关闭按钮 computeBgColor() {
close() { if (this.bgColor) return this.bgColor;
this.$emit('close'); return this.$u.color[this.type + 'Light'];
} },
} computeBorderColor() {
} if (this.borderColor) return this.borderColor;
</script> return this.$u.color[this.type + 'Disabled'];
}
<style lang="scss" scoped> },
.u-alert-tips { methods: {
display: flex; // 点击内容
align-items: center; click() {
padding: 16rpx 30rpx; this.$emit('click');
border-radius: 8rpx; },
position: relative; // 点击关闭按钮
transition: all 0.3s linear; close() {
border: 1px solid #fff; this.$emit('close');
} }
}
.u-close-alert-tips { }
opacity: 0; </script>
visibility: hidden;
} <style lang="scss" scoped>
.u-alert-tips {
@keyframes myfirst { display: flex;
from { align-items: center;
height: 100%; padding: 16rpx 30rpx;
} border-radius: 8rpx;
position: relative;
to { transition: all 0.3s linear;
height: 0 border: 1px solid #fff;
} }
}
.u-close-alert-tips {
.u-icon { opacity: 0;
margin-right: 16rpx; visibility: hidden;
} }
.u-alert-title { @keyframes myfirst {
font-size: 28rpx; from {
color: $u-main-color; height: 100%;
} }
.u-alert-desc { to {
font-size: 26rpx; height: 0
text-align: left; }
color: $u-content-color; }
}
.u-icon {
.u-close-icon { margin-right: 16rpx;
position: absolute; }
top: 20rpx;
right: 20rpx; .u-alert-title {
} font-size: 28rpx;
color: $u-main-color;
.u-close-hover { }
color: red;
} .u-alert-desc {
font-size: 26rpx;
.u-close-text { text-align: left;
font-size: 24rpx; color: $u-content-color;
color: $u-tips-color; }
position: absolute;
top: 20rpx; .u-close-icon {
right: 20rpx; position: absolute;
line-height: 1; top: 20rpx;
} right: 20rpx;
}
.u-close-hover {
color: red;
}
.u-close-text {
font-size: 24rpx;
color: $u-tips-color;
position: absolute;
top: 20rpx;
right: 20rpx;
line-height: 1;
}
</style> </style>
...@@ -7,6 +7,16 @@ ...@@ -7,6 +7,16 @@
</template> </template>
<script> <script>
/**
* alertTips 提示
* @description 该组件一般的图片裁剪需求场景,尤其适合于头像裁剪方面。
* @tutorial https://www.uviewui.com/components/avatarCropper.html
* @property {String Number} dest-width 输出图片宽度,高等于宽,单位px(默认200)
* @property {String Number} rect-width 裁剪框宽度,高等于宽,单位px(默认200)
* @property {String} file-type 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可(默认jpg)
* @event {Function} uAvatarCropper 裁剪结束后的事件,通过uni.$on监听
* @example <image class="u-avatar-demo" :src="avatar" mode="aspectFill"></image>
*/
let base64Avatar = "data:image/png;base64,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"; let base64Avatar = "data:image/png;base64,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";
export default { export default {
props: { props: {
......
<template> <template>
<view v-if="show" class="u-badge-box" :class="[isDot ? 'u-badge-dot' : 'u-badge', size == 'mini' ? 'u-badge-mini' : '']" :style="[{ <view v-if="show" class="u-badge-box" :class="[isDot ? 'u-badge-dot' : 'u-badge', size == 'mini' ? 'u-badge-mini' : '']"
top: offset[0] + 'rpx', :style="[{
right: offset[1] + 'rpx', top: offset[0] + 'rpx',
fontSize: fontSize + 'rpx', right: offset[1] + 'rpx',
position: absolute ? 'absolute' : 'static', fontSize: fontSize + 'rpx',
color: color, position: absolute ? 'absolute' : 'static',
backgroundColor: backgroundColor color: color,
}, boxStyle]"> backgroundColor: backgroundColor
{{showText}} }, boxStyle]">
</view> {{showText}}
</template> </view>
</template>
<script>
export default { <script>
props: { /**
// primary,warning,success,error,info * alertTips 提示
type: { * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
type: String, * @tutorial https://www.uviewui.com/components/badge.html
default: 'error' * @property {String Number} count 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为0且show-zero为false时隐藏
}, * @property {Boolean} is-dot 不展示数字,只有一个小点(默认false)
// default, mini * @property {Boolean} absolute 组件是否绝对定位,为true时,offset参数才有效(默认true)
size: { * @property {String Number} overflow-count 展示封顶的数字值(默认99)
type: String, * @property {String} type 使用预设的背景颜色(默认error)
default: 'default' * @property {Boolean} show-zero 当数值为 0 时,是否展示 Badge(默认false)
}, * @property {String} size Badge的尺寸,设为mini会得到小一号的Badge(默认default)
//是否是圆点 * @property {Array} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,单位rpx。absolute为true时有效(默认[20, 20])
isDot: { * @property {String} color 字体颜色(默认#ffffff)
type: Boolean, * @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
default: false * @property {Boolean} is-center 组件中心点是否和父组件右上角重合,优先级比offset高,如设置,offset参数会失效(默认false)
}, * @example <u-badge type="error" count="7"></u-badge>
// 显示的数值内容 */
count: { export default {
type: [Number, String], name: "u-badge",
}, props: {
// 展示封顶的数字值 // primary,warning,success,error,info
overflowCount: { type: {
type: Number, type: String,
default: 99 default: 'error'
}, },
// 当数值为 0 时,是否展示 Badge // default, mini
showZero: { size: {
type: Boolean, type: String,
default: false default: 'default'
}, },
// 位置偏移 //是否是圆点
offset: { isDot: {
type: Array, type: Boolean,
default: () => { default: false
return [20, 20] },
} // 显示的数值内容
}, count: {
// 是否开启绝对定位,开启了offset才会起作用 type: [Number, String],
absolute: { },
type: Boolean, // 展示封顶的数字值
default: true overflowCount: {
}, type: Number,
// 字体大小 default: 99
fontSize: { },
type: [String, Number], // 当数值为 0 时,是否展示 Badge
default: '24' showZero: {
}, type: Boolean,
// 字体演示 default: false
color: { },
type: String, // 位置偏移
default: '#ffffff' offset: {
}, type: Array,
// badge的背景颜色 default: () => {
bgColor: { return [20, 20]
type: String, }
default: '' },
}, // 是否开启绝对定位,开启了offset才会起作用
// 是否让badge组件的中心点和父组件右上角重合,配置的话,offset将会失效 absolute: {
isCenter: { type: Boolean,
type: Boolean, default: true
default: false },
} // 字体大小
}, fontSize: {
computed: { type: [String, Number],
// 是否将badge中心与父组件右上角重合 default: '24'
boxStyle() { },
let style = {}; // 字体演示
if(this.isCenter) { color: {
style.top = 0; type: String,
style.right = 0; default: '#ffffff'
// Y轴-50%,意味着badge向上移动了badge自身高度一半,X轴50%,意味着向右移动了自身宽度一半 },
style.transform = "translateY(-50%) translateX(50%)"; // badge的背景颜色
} else { bgColor: {
style.top = this.offset[0] + 'rpx'; type: String,
style.right = this.offset[1] + 'rpx'; default: ''
style.transform = "translateY(0) translateX(0)"; },
} // 是否让badge组件的中心点和父组件右上角重合,配置的话,offset将会失效
return style; isCenter: {
}, type: Boolean,
// isDot类型时,不显示文字 default: false
showText() { }
if(this.isDot) return ''; },
else { computed: {
if(this.count > this.overflowCount) return `${this.overflowCount}+`; // 是否将badge中心与父组件右上角重合
else return this.count; boxStyle() {
} let style = {};
}, if (this.isCenter) {
// 是否显示组件 style.top = 0;
show() { style.right = 0;
// 如果count的值为0,并且showZero设置为false,不显示组件 // Y轴-50%,意味着badge向上移动了badge自身高度一半,X轴50%,意味着向右移动了自身宽度一半
if(this.count == 0 && this.showZero == false) return false; style.transform = "translateY(-50%) translateX(50%)";
else return true; } else {
}, style.top = this.offset[0] + 'rpx';
// 获取背景颜色,如果定义了bgColor参数,就放弃type主题色 style.right = this.offset[1] + 'rpx';
backgroundColor() { style.transform = "translateY(0) translateX(0)";
return this.bgColor ? this.bgColor : this.$u.color[this.type]; }
} return style;
} },
} // isDot类型时,不显示文字
</script> showText() {
if (this.isDot) return '';
<style lang="scss" scoped> else {
.u-badge-box { if (this.count > this.overflowCount) return `${this.overflowCount}+`;
display: inline-flex; else return this.count;
justify-content: center; }
align-items: center; },
} // 是否显示组件
show() {
.u-badge { // 如果count的值为0,并且showZero设置为false,不显示组件
line-height: 24rpx; if (this.count == 0 && this.showZero == false) return false;
padding: 4rpx 8rpx; else return true;
border-radius: 100rpx; },
} // 获取背景颜色,如果定义了bgColor参数,就放弃type主题色
backgroundColor() {
.u-badge-dot { return this.bgColor ? this.bgColor : this.$u.color[this.type];
height: 16rpx; }
width: 16rpx; }
border-radius: 100rpx; }
line-height: 1; </script>
}
<style lang="scss" scoped>
.u-badge-mini { .u-badge-box {
transform: scale(0.8); display: inline-flex;
transform-origin: center center; justify-content: center;
} align-items: center;
}
// .u-primary {
// background: $u-type-primary; .u-badge {
// color: #fff; line-height: 24rpx;
// } padding: 4rpx 8rpx;
border-radius: 100rpx;
// .u-error { }
// background: $u-type-error;
// color: #fff; .u-badge-dot {
// } height: 16rpx;
width: 16rpx;
// .u-warning { border-radius: 100rpx;
// background: $u-type-warning; line-height: 1;
// color: #fff; }
// }
.u-badge-mini {
// .u-success { transform: scale(0.8);
// background: $u-type-success; transform-origin: center center;
// color: #fff; }
// }
// .u-primary {
// .u-black { // background: $u-type-primary;
// background: #585858; // color: #fff;
// color: #fff; // }
// }
// .u-error {
.u-info { // background: $u-type-error;
background: $u-type-info; // color: #fff;
color: #fff; // }
}
</style> // .u-warning {
\ No newline at end of file // background: $u-type-warning;
// color: #fff;
// }
// .u-success {
// background: $u-type-success;
// color: #fff;
// }
// .u-black {
// background: #585858;
// color: #fff;
// }
.u-info {
background: $u-type-info;
color: #fff;
}
</style>
<template> <template>
<button id="u-wave-btn" class="u-btn u-line-1 u-fix-ios-appearance" :class="[ <button id="u-wave-btn" class="u-btn u-line-1 u-fix-ios-appearance" :class="[
'u-size-' + size, 'u-size-' + size,
plain ? 'u-' + type + '-plain' : '', plain ? 'u-' + type + '-plain' : '',
loading ? 'u-loading' : '', loading ? 'u-loading' : '',
shape == 'circle' ? 'u-round-circle' : '', shape == 'circle' ? 'u-round-circle' : '',
hairLine ? showHairLineBorder : 'u-bold-border', hairLine ? showHairLineBorder : 'u-bold-border',
]" ]"
:disabled="disabled" :disabled="disabled" :form-type="formType" :open-type="openType" :app-parameter="appParameter"
:form-type="formType" :hover-stop-propagation="hoverStopPropagation" :send-message-title="sendMessageTitle" send-message-path="sendMessagePath"
:open-type="openType" :lang="lang" :session-from="sessionFrom" :send-message-img="sendMessageImg" :show-message-card="showMessageCard"
:app-parameter="appParameter" @getphonenumber="getphonenumber" @getuserinfo="getuserinfo" @error="error" @opensetting="opensetting" @launchapp="launchapp"
:hover-stop-propagation="hoverStopPropagation" :style="[buttonStyle]" @tap="click($event)" :hover-class="getHoverClass" :loading="loading">
:send-message-title="sendMessageTitle" <slot></slot>
send-message-path="sendMessagePath" <view v-if="ripple" class="u-wave-ripple" :class="[waveActive ? 'u-wave-active' : '']" :style="{
:lang="lang" 'top': rippleTop + 'px',
:session-from="sessionFrom" 'left': rippleLeft + 'px',
:send-message-img="sendMessageImg" 'width': fields.targetWidth + 'px',
:show-message-card="showMessageCard" 'height': fields.targetWidth + 'px',
@getphonenumber="getphonenumber" 'background-color': (rippleBgColor || 'rgba(0, 0, 0, 0.15)')
@getuserinfo="getuserinfo" }">
@error="error" </view>
@opensetting="opensetting" </button>
@launchapp="launchapp" </template>
:style="[buttonStyle]" @tap="click($event)" :hover-class="getHoverClass" :loading="loading">
<slot></slot> <script>
<view v-if="ripple" class="u-wave-ripple" :class="[waveActive ? 'u-wave-active' : '']" :style="{ /**
'top': rippleTop + 'px', * alertTips 提示
'left': rippleLeft + 'px', * @description Button 按钮
'width': fields.targetWidth + 'px', * @tutorial https://www.uviewui.com/components/button.html
'height': fields.targetWidth + 'px', * @property {String} size 按钮的大小
'background-color': (rippleBgColor || 'rgba(0, 0, 0, 0.15)') * @property {Boolean} ripple 是否开启点击水波纹效果
}"> * @property {String} ripple-bg-color 水波纹的背景色,ripple为true时有效
</view> * @property {String} type 按钮的样式类型
</button> * @property {Boolean} plain 按钮是否镂空,背景色透明
</template> * @property {Boolean} disabled 是否禁用
* @property {Boolean} shape 按钮外观形状,见文档说明
<script> * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈)
* @property {String} form-type 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
* @property {String} open-type 开放能力
* @property {String} hover-class 指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果(App-nvue 平台暂不支持)
* @property {Number} hover-start-time 按住后多久出现点击态,单位毫秒
* @property {Number} hover-stay-time 手指松开后点击态保留时间,单位毫秒
* @property {Object} custom-style 对按钮的自定义样式,对象形式,见文档说明
* @event {Function} click 按钮点击
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
* @event {Function} error 当使用开放能力时,发生错误的回调
* @event {Function} opensetting 在打开授权设置页并关闭后回调
* @event {Function} launchapp 打开 APP 成功的回调
* @example <u-button>月落</u-button>
*/
export default { export default {
props: { name:"u-button",
// 是否细边框 props: {
hairLine: { // 是否细边框
type: Boolean, hairLine: {
default: true type: Boolean,
}, default: true
// 按钮的预置样式,default,primary,error,warning,success },
type: { // 按钮的预置样式,default,primary,error,warning,success
type: String, type: {
default: 'default' type: String,
}, default: 'default'
// 按钮尺寸,default,medium,mini },
size: { // 按钮尺寸,default,medium,mini
type: String, size: {
default: 'default' type: String,
}, default: 'default'
// 按钮形状,circle(两边为半圆),square(带圆角) },
shape: { // 按钮形状,circle(两边为半圆),square(带圆角)
type: String, shape: {
default: 'square' type: String,
}, default: 'square'
// 按钮是否镂空 },
plain: { // 按钮是否镂空
type: Boolean, plain: {
default: false type: Boolean,
}, default: false
// 是否禁止状态 },
disabled: { // 是否禁止状态
type: Boolean, disabled: {
default: false type: Boolean,
}, default: false
// 是否加载中 },
loading: { // 是否加载中
type: Boolean, loading: {
default: false type: Boolean,
}, default: false
// 开放能力,具体请看uniapp稳定关于button组件部分说明 },
// https://uniapp.dcloud.io/component/button // 开放能力,具体请看uniapp稳定关于button组件部分说明
openType: { // https://uniapp.dcloud.io/component/button
type: String, openType: {
default: '' type: String,
}, default: ''
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件 },
// 取值为submit(提交表单),reset(重置表单) // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
formType: { // 取值为submit(提交表单),reset(重置表单)
type: String, formType: {
default: '' type: String,
}, default: ''
// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 },
// 只微信小程序、QQ小程序有效 // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
appParameter: { // 只微信小程序、QQ小程序有效
type: String, appParameter: {
default: '' type: String,
}, default: ''
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效 },
hoverStopPropagation: { // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
type: Boolean, hoverStopPropagation: {
default: false type: Boolean,
}, default: false
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效 },
lang: { // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
type: String, lang: {
default: 'en' type: String,
}, default: 'en'
// 会话来源,open-type="contact"时有效。只微信小程序有效 },
sessionFrom: { // 会话来源,open-type="contact"时有效。只微信小程序有效
type: String, sessionFrom: {
default: '' type: String,
}, default: ''
// 会话内消息卡片标题,open-type="contact"时有效 },
// 默认当前标题,只微信小程序有效 // 会话内消息卡片标题,open-type="contact"时有效
sendMessageTitle: { // 默认当前标题,只微信小程序有效
type: String, sendMessageTitle: {
default: '' type: String,
}, default: ''
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效 },
// 默认当前分享路径,只微信小程序有效 // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
sendMessagePath: { // 默认当前分享路径,只微信小程序有效
type: String, sendMessagePath: {
default: '' type: String,
}, default: ''
// 会话内消息卡片图片,open-type="contact"时有效 },
// 默认当前页面截图,只微信小程序有效 // 会话内消息卡片图片,open-type="contact"时有效
sendMessageImg: { // 默认当前页面截图,只微信小程序有效
type: String, sendMessageImg: {
default: '' type: String,
}, default: ''
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示, },
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效 // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
showMessageCard: { // 用户点击后可以快速发送小程序消息,open-type="contact"时有效
type: Boolean, showMessageCard: {
default: false type: Boolean,
}, default: false
// 手指按(触摸)按钮时按钮时的背景颜色 },
hoverBgColor: { // 手指按(触摸)按钮时按钮时的背景颜色
type: String, hoverBgColor: {
default: '' type: String,
}, default: ''
// 水波纹的背景颜色 },
rippleBgColor: { // 水波纹的背景颜色
type: String, rippleBgColor: {
default: '' type: String,
}, default: ''
// 是否开启水波纹效果 },
ripple: { // 是否开启水波纹效果
type: Boolean, ripple: {
default: false type: Boolean,
}, default: false
// 按下的类名 },
hoverClass: { // 按下的类名
type: String, hoverClass: {
default: '' type: String,
}, default: ''
// 自定义样式,对象形式 },
customStyle: { // 自定义样式,对象形式
type: Object, customStyle: {
default() { type: Object,
return {} default () {
} return {}
} }
}, }
computed: { },
// 当没有传bgColor变量时,按钮按下去的颜色类名 computed: {
getHoverClass() { // 当没有传bgColor变量时,按钮按下去的颜色类名
// 如果开启水波纹效果,则不启用hover-class效果 getHoverClass() {
if (this.loading || this.disabled || this.ripple || this.hoverClass) return ''; // 如果开启水波纹效果,则不启用hover-class效果
let hoverClass = ''; if (this.loading || this.disabled || this.ripple || this.hoverClass) return '';
hoverClass = this.plain ? 'u-' + this.type + '-plain-hover' : 'u-' + this.type + '-hover'; let hoverClass = '';
return hoverClass; hoverClass = this.plain ? 'u-' + this.type + '-plain-hover' : 'u-' + this.type + '-hover';
}, return hoverClass;
// 按钮主题 },
buttonStyle() { // 按钮主题
let style = {}; buttonStyle() {
if (this.type == 'default') { let style = {};
if (this.disabled) { if (this.type == 'default') {
style.color = "#c0c4cc"; if (this.disabled) {
style.backgroundColor = "#ffffff"; style.color = "#c0c4cc";
style.borderColor = "#e4e7ed"; style.backgroundColor = "#ffffff";
} else { style.borderColor = "#e4e7ed";
style.color = this.$u.color['contentColor']; } else {
style.backgroundColor = "#ffffff"; style.color = this.$u.color['contentColor'];
style.borderColor = "#c0c4cc"; style.backgroundColor = "#ffffff";
} style.borderColor = "#c0c4cc";
} else { }
if (this.disabled) { } else {
if(this.plain) { if (this.disabled) {
style.color = this.$u.color[this.type + 'Disabled']; if (this.plain) {
style.backgroundColor = this.$u.color[this.type + 'Light']; style.color = this.$u.color[this.type + 'Disabled'];
style.borderColor = this.$u.color[this.type + 'Disabled']; style.backgroundColor = this.$u.color[this.type + 'Light'];
} else { style.borderColor = this.$u.color[this.type + 'Disabled'];
style.color = "#ffffff"; } else {
style.backgroundColor = this.$u.color[this.type + 'Disabled']; style.color = "#ffffff";
style.borderColor = this.$u.color[this.type + 'Disabled']; style.backgroundColor = this.$u.color[this.type + 'Disabled'];
} style.borderColor = this.$u.color[this.type + 'Disabled'];
} else { }
if(this.plain) { } else {
style.color = this.$u.color[this.type] if (this.plain) {
style.backgroundColor = this.$u.color[this.type + 'Light']; style.color = this.$u.color[this.type]
style.borderColor = this.$u.color[this.type + 'Disabled']; style.backgroundColor = this.$u.color[this.type + 'Light'];
} else { style.borderColor = this.$u.color[this.type + 'Disabled'];
style.color = "#ffffff"; } else {
style.backgroundColor = this.$u.color[this.type]; style.color = "#ffffff";
style.borderColor = this.$u.color[this.type]; style.backgroundColor = this.$u.color[this.type];
} style.borderColor = this.$u.color[this.type];
} }
} }
}
return Object.assign(style, this.customStyle);
}, return Object.assign(style, this.customStyle);
// 在'primary', 'success', 'error', 'warning'类型下,不显示边框,否则会造成四角有毛刺现象 },
showHairLineBorder() { // 在'primary', 'success', 'error', 'warning'类型下,不显示边框,否则会造成四角有毛刺现象
if(['primary', 'success', 'error', 'warning'].indexOf(this.type) >= 0 && !this.plain) { showHairLineBorder() {
return ''; if (['primary', 'success', 'error', 'warning'].indexOf(this.type) >= 0 && !this.plain) {
} else { return '';
return 'u-hairline-border'; } else {
} return 'u-hairline-border';
} }
}, }
data() { },
return { data() {
rippleTop: 0, // 水波纹的起点Y坐标到按钮上边界的距离 return {
rippleLeft: 0, // 水波纹起点X坐标到按钮左边界的距离 rippleTop: 0, // 水波纹的起点Y坐标到按钮上边界的距离
fields: {}, // 波纹按钮节点信息 rippleLeft: 0, // 水波纹起点X坐标到按钮左边界的距离
waveActive: false, // 激活水波纹 fields: {}, // 波纹按钮节点信息
} waveActive: false, // 激活水波纹
}, }
methods: { },
// 按钮点击 methods: {
click(e) { // 按钮点击
// 如果按钮时disabled和loading状态,不触发水波纹效果 click(e) {
if (this.loading === true || this.disabled === true) return; // 如果按钮时disabled和loading状态,不触发水波纹效果
// 是否开启水波纹效果 if (this.loading === true || this.disabled === true) return;
if (this.ripple) { // 是否开启水波纹效果
// 每次点击时,移除上一次的类,再次添加,才能触发动画效果 if (this.ripple) {
this.waveActive = false; // 每次点击时,移除上一次的类,再次添加,才能触发动画效果
this.$nextTick(function() { this.waveActive = false;
this.getWaveQuery(e); this.$nextTick(function() {
}); this.getWaveQuery(e);
} });
this.$emit('click'); }
}, this.$emit('click');
// 查询按钮的节点信息 },
getWaveQuery(e) { // 查询按钮的节点信息
this.getElQuery().then(res => { getWaveQuery(e) {
// 查询返回的是一个数组节点 this.getElQuery().then(res => {
let data = res[0]; // 查询返回的是一个数组节点
// 查询不到节点信息,不操作 let data = res[0];
if (!data.width || !data.width) return; // 查询不到节点信息,不操作
// 水波纹的最终形态是一个正方形(通过border-radius让其变为一个圆形),这里要保证正方形的边长等于按钮的最长边 if (!data.width || !data.width) return;
// 最终的方形(变换后的圆形)才能覆盖整个按钮 // 水波纹的最终形态是一个正方形(通过border-radius让其变为一个圆形),这里要保证正方形的边长等于按钮的最长边
data.targetWidth = (data.height > data.width ? data.height : data.width); // 最终的方形(变换后的圆形)才能覆盖整个按钮
if (!data.targetWidth) return; data.targetWidth = (data.height > data.width ? data.height : data.width);
this.fields = data; if (!data.targetWidth) return;
let touchesX = '', this.fields = data;
touchesY = ''; let touchesX = '',
// #ifdef MP-BAIDU touchesY = '';
touchesX = e.changedTouches[0].clientX; // #ifdef MP-BAIDU
touchesY = e.changedTouches[0].clientY; touchesX = e.changedTouches[0].clientX;
// #endif touchesY = e.changedTouches[0].clientY;
// #ifdef MP-ALIPAY // #endif
touchesX = e.detail.clientX; // #ifdef MP-ALIPAY
touchesY = e.detail.clientY; touchesX = e.detail.clientX;
// #endif touchesY = e.detail.clientY;
// #ifndef MP-BAIDU || MP-ALIPAY // #endif
touchesX = e.touches[0].clientX; // #ifndef MP-BAIDU || MP-ALIPAY
touchesY = e.touches[0].clientY; touchesX = e.touches[0].clientX;
// #endif touchesY = e.touches[0].clientY;
// 获取触摸点相对于按钮上边和左边的x和y坐标,原理是通过屏幕的触摸点(touchesY),减去按钮的上边界data.top // #endif
// 但是由于`transform-origin`默认是center,所以这里再减去半径才是水波纹view应该的位置 // 获取触摸点相对于按钮上边和左边的x和y坐标,原理是通过屏幕的触摸点(touchesY),减去按钮的上边界data.top
// 总的来说,就是把水波纹的矩形(变换后的圆形)的中心点,移动到我们的触摸点位置 // 但是由于`transform-origin`默认是center,所以这里再减去半径才是水波纹view应该的位置
this.rippleTop = (touchesY - data.top - (data.targetWidth / 2)); // 总的来说,就是把水波纹的矩形(变换后的圆形)的中心点,移动到我们的触摸点位置
this.rippleLeft = (touchesX - data.left - (data.targetWidth / 2)); this.rippleTop = (touchesY - data.top - (data.targetWidth / 2));
this.$nextTick(() => { this.rippleLeft = (touchesX - data.left - (data.targetWidth / 2));
this.waveActive = true; this.$nextTick(() => {
}) this.waveActive = true;
}) })
}, })
// 获取节点信息 },
getElQuery() { // 获取节点信息
return new Promise(resolve => { getElQuery() {
let queryInfo = ''; return new Promise(resolve => {
// 获取元素节点信息,请查看uniapp相关文档 let queryInfo = '';
// https://uniapp.dcloud.io/api/ui/nodes-info?id=nodesrefboundingclientrect // 获取元素节点信息,请查看uniapp相关文档
queryInfo = uni.createSelectorQuery().in(this); // https://uniapp.dcloud.io/api/ui/nodes-info?id=nodesrefboundingclientrect
queryInfo.select('.u-btn').boundingClientRect(); queryInfo = uni.createSelectorQuery().in(this);
queryInfo.exec((data) => { queryInfo.select('.u-btn').boundingClientRect();
resolve(data) queryInfo.exec((data) => {
}); resolve(data)
}) });
}, })
// 下面为对接uniapp官方按钮开放能力事件回调的对接 },
getphonenumber(res) { // 下面为对接uniapp官方按钮开放能力事件回调的对接
this.$emit('getphonenumber', res); getphonenumber(res) {
}, this.$emit('getphonenumber', res);
getuserinfo(res) { },
this.$emit('getuserinfo', res); getuserinfo(res) {
}, this.$emit('getuserinfo', res);
error(res) { },
this.$emit('error', res); error(res) {
}, this.$emit('error', res);
opensetting(res) { },
this.$emit('opensetting', res); opensetting(res) {
}, this.$emit('opensetting', res);
launchapp(res) { },
this.$emit('launchapp', res); launchapp(res) {
}, this.$emit('launchapp', res);
} },
} }
</script> }
</script>
<style scoped lang="scss">
button::after { <style scoped lang="scss">
border: none; button::after {
} border: none;
}
.u-btn {
position: relative; .u-btn {
border: 0; position: relative;
//border-radius: 10rpx; border: 0;
display: inline-block; //border-radius: 10rpx;
overflow: hidden; display: inline-block;
line-height: 1; overflow: hidden;
display: flex; line-height: 1;
align-items: center; display: flex;
justify-content: center; align-items: center;
cursor: pointer; justify-content: center;
padding: 0 40rpx; cursor: pointer;
z-index: 1; padding: 0 40rpx;
box-sizing: border-box; z-index: 1;
transition: all 0.15s; box-sizing: border-box;
} transition: all 0.15s;
}
.u-hairline-border:after {
content: ' '; .u-hairline-border:after {
position: absolute; content: ' ';
pointer-events: none; position: absolute;
// 设置为border-box,意味着下面的scale缩小为0.5,实际上缩小的是伪元素的内容(border-box意味着内容不含border) pointer-events: none;
box-sizing: border-box; // 设置为border-box,意味着下面的scale缩小为0.5,实际上缩小的是伪元素的内容(border-box意味着内容不含border)
// 中心点作为变形(scale())的原点 box-sizing: border-box;
-webkit-transform-origin: 0 0; // 中心点作为变形(scale())的原点
transform-origin: 0 0; -webkit-transform-origin: 0 0;
left: 0; transform-origin: 0 0;
top: 0; left: 0;
width: 200%; top: 0;
height: 200%; width: 200%;
-webkit-transform: scale(0.5, 0.5); height: 200%;
transform: scale(0.5, 0.5); -webkit-transform: scale(0.5, 0.5);
border: 1px solid currentColor; transform: scale(0.5, 0.5);
z-index: 0; border: 1px solid currentColor;
} z-index: 0;
}
.u-bold-border {
border: 1px solid #FFFFFF; .u-bold-border {
} border: 1px solid #FFFFFF;
}
.u-wave-ripple {
z-index: 0; .u-wave-ripple {
position: absolute; z-index: 0;
border-radius: 100%; position: absolute;
background-clip: padding-box; border-radius: 100%;
pointer-events: none; background-clip: padding-box;
user-select: none; pointer-events: none;
transform: scale(0); user-select: none;
opacity: 1; transform: scale(0);
transform-origin: center; opacity: 1;
} transform-origin: center;
}
.u-wave-ripple.u-wave-active {
opacity: 0; .u-wave-ripple.u-wave-active {
transform: scale(2); opacity: 0;
transition: opacity 1s linear, transform 0.4s linear; transform: scale(2);
} transition: opacity 1s linear, transform 0.4s linear;
}
.u-round-circle {
border-radius: 100rpx; .u-round-circle {
} border-radius: 100rpx;
}
.u-round-circle::after {
border-radius: 100rpx; .u-round-circle::after {
} border-radius: 100rpx;
}
.u-loading::after {
background-color: hsla(0, 0%, 100%, .35); .u-loading::after {
} background-color: hsla(0, 0%, 100%, .35);
}
.u-size-default {
font-size: 30rpx; .u-size-default {
height: 80rpx; font-size: 30rpx;
line-height: 80rpx; height: 80rpx;
} line-height: 80rpx;
}
.u-size-medium {
display: inline-flex; .u-size-medium {
width: auto; display: inline-flex;
font-size: 26rpx; width: auto;
height: 70rpx; font-size: 26rpx;
line-height: 70rpx; height: 70rpx;
padding: 0 80rpx; line-height: 70rpx;
} padding: 0 80rpx;
}
.u-size-mini {
display: inline-flex; .u-size-mini {
width: auto; display: inline-flex;
font-size: 22rpx; width: auto;
padding-top: 1px; font-size: 22rpx;
height: 50rpx; padding-top: 1px;
line-height: 50rpx; height: 50rpx;
padding: 0 20rpx; line-height: 50rpx;
} padding: 0 20rpx;
}
.u-primary-plain-hover {
color: #FFFFFF!important; .u-primary-plain-hover {
background: $u-type-primary-dark !important; color: #FFFFFF !important;
} background: $u-type-primary-dark !important;
}
.u-default-plain-hover {
color: $u-type-primary-dark !important; .u-default-plain-hover {
background: $u-type-primary-light !important; color: $u-type-primary-dark !important;
} background: $u-type-primary-light !important;
}
.u-success-plain-hover {
color: #FFFFFF!important; .u-success-plain-hover {
background: $u-type-success-dark!important; color: #FFFFFF !important;
} background: $u-type-success-dark !important;
}
.u-warning-plain-hover {
color: #FFFFFF!important; .u-warning-plain-hover {
background: $u-type-warning-dark !important; color: #FFFFFF !important;
} background: $u-type-warning-dark !important;
}
.u-error-plain-hover {
color: #FFFFFF!important; .u-error-plain-hover {
background: $u-type-error-dark !important; color: #FFFFFF !important;
} background: $u-type-error-dark !important;
}
.u-info-plain-hover {
color: #FFFFFF!important; .u-info-plain-hover {
background: $u-type-info-dark !important; color: #FFFFFF !important;
} background: $u-type-info-dark !important;
}
.u-default-hover {
color: $u-type-primary-dark !important; .u-default-hover {
border-color: $u-type-primary-dark !important; color: $u-type-primary-dark !important;
background-color: $u-type-primary-light !important;; border-color: $u-type-primary-dark !important;
} background-color: $u-type-primary-light !important;
;
.u-primary-hover { }
background: $u-type-primary-dark !important;
color: #fff; .u-primary-hover {
} background: $u-type-primary-dark !important;
color: #fff;
.u-success-hover { }
background: $u-type-success-dark !important;
color: #fff; .u-success-hover {
} background: $u-type-success-dark !important;
color: #fff;
.u-info-hover { }
background: $u-type-info-dark !important;
color: #fff; .u-info-hover {
} background: $u-type-info-dark !important;
color: #fff;
.u-warning-hover { }
background: $u-type-warning-dark !important;
color: #fff; .u-warning-hover {
} background: $u-type-warning-dark !important;
color: #fff;
.u-error-hover { }
background: $u-type-error-dark !important;
color: #fff; .u-error-hover {
} background: $u-type-error-dark !important;
color: #fff;
}
</style> </style>
<template> <template>
<view class="u-keyboard" @touchmove.stop.prevent> <view class="u-keyboard" @touchmove.stop.prevent>
<view class="u-keyboard-grids"> <view class="u-keyboard-grids">
<block> <block>
<view class="u-keyboard-grids-item" v-for="(group, i) in abc ? EngKeyBoardList : areaList" :key="i"> <view class="u-keyboard-grids-item" v-for="(group, i) in abc ? EngKeyBoardList : areaList" :key="i">
<view :hover-stay-time="100" @tap="carInputClick(i, j)" hover-class="u-carinput-hover" class="u-keyboard-grids-btn" v-for="(item, j) in group" :key="j"> <view :hover-stay-time="100" @tap="carInputClick(i, j)" hover-class="u-carinput-hover" class="u-keyboard-grids-btn"
{{ item }} v-for="(item, j) in group" :key="j">
</view> {{ item }}
</view> </view>
<view @touchstart="backspaceClick" @touchend="clearTimer" :hover-stay-time="100" class="u-keyboard-back" hover-class="u-hover-class"> </view>
<u-icon :size="38" name="backspace" :bold="true"></u-icon> <view @touchstart="backspaceClick" @touchend="clearTimer" :hover-stay-time="100" class="u-keyboard-back"
</view> hover-class="u-hover-class">
<view :hover-stay-time="100" class="u-keyboard-change" hover-class="u-carinput-hover" @tap="changeCarInputMode"> <u-icon :size="38" name="backspace" :bold="true"></u-icon>
<text class="zh" :class="[!abc ? 'active' : 'inactive']"></text> </view>
/ <view :hover-stay-time="100" class="u-keyboard-change" hover-class="u-carinput-hover" @tap="changeCarInputMode">
<text class="en" :class="[abc ? 'active' : 'inactive']"></text> <text class="zh" :class="[!abc ? 'active' : 'inactive']"></text>
</view> /
</block> <text class="en" :class="[abc ? 'active' : 'inactive']"></text>
</view> </view>
</view> </block>
</template> </view>
</view>
<script> </template>
export default {
props: { <script>
// 是否打乱键盘按键的顺序 /**
random: { * alertTips 提示
type: Boolean, * @description 此为uViw自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3中模式,都有可以打乱按键顺序的选项。
default: false * @tutorial https://www.uviewui.com/components/keyboard.html
} * @property {String} mode 键盘类型,见官网基本使用的说明(默认number)
}, * @property {Boolean} dot-enabled 是否显示"."按键,只在mode=number时有效(默认true)
data() { * @property {Boolean} tooltip 是否显示键盘顶部工具条(默认true)
return { * @property {String} tips 工具条中间的提示文字,见官网基本使用的说明,如不需要,请传""空字符
// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称 * @property {Boolean} cancel-btn 是否显示工具条左边的"取消"按钮(默认true)
abc: false * @property {Boolean} confirm-btn 是否显示工具条右边的"完成"按钮(默认true)
}; * @property {Boolean} mask 是否显示遮罩(默认true)
}, * @property {Number String} z-index 弹出键盘的z-index值(默认1075)
computed: { * @property {Boolean} random 是否打乱键盘按键的顺序(默认false)
areaList() { * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
let data = [ * @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: {
'', // 是否打乱键盘按键的顺序
'', random: {
'', type: Boolean,
'', default: false
'', }
'', },
'', data() {
'', return {
'', // 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
'', abc: false
'', };
'', },
'', computed: {
'', areaList() {
'', let data = [
'', '',
'', '',
'', '',
'', '',
'', '',
'', '',
'', '',
'', '',
'', '',
'', '',
'使', '',
'' '',
]; '',
let tmp = []; '',
// 打乱顺序 '',
if (this.random) data = this.$u.randomArray(data); '',
// 切割成二维数组 '',
tmp[0] = data.slice(0, 10); '',
tmp[1] = data.slice(10, 20); '',
tmp[2] = data.slice(20, 30); '',
tmp[3] = data.slice(30, 36); '',
return tmp; '',
}, '',
EngKeyBoardList() { '',
let data = [ '',
1, '',
2, '',
3, '',
4, '',
5, '',
6, '',
7, '',
8, '',
9, '',
0, '使',
'Q', ''
'W', ];
'E', let tmp = [];
'R', // 打乱顺序
'T', if (this.random) data = this.$u.randomArray(data);
'Y', // 切割成二维数组
'U', tmp[0] = data.slice(0, 10);
'I', tmp[1] = data.slice(10, 20);
'O', tmp[2] = data.slice(20, 30);
'P', tmp[3] = data.slice(30, 36);
'A', return tmp;
'S', },
'D', EngKeyBoardList() {
'F', let data = [
'G', 1,
'H', 2,
'J', 3,
'K', 4,
'L', 5,
'Z', 6,
'X', 7,
'C', 8,
'V', 9,
'B', 0,
'N', 'Q',
'M' 'W',
]; 'E',
let tmp = []; 'R',
if (this.random) data = this.$u.randomArray(data); 'T',
tmp[0] = data.slice(0, 10); 'Y',
tmp[1] = data.slice(10, 20); 'U',
tmp[2] = data.slice(20, 30); 'I',
tmp[3] = data.slice(30, 36); 'O',
return tmp; 'P',
} 'A',
}, 'S',
methods: { 'D',
// 点击键盘按钮 'F',
carInputClick(i, j) { 'G',
let value = ''; 'H',
// 不同模式,获取不同数组的值 'J',
if (this.abc) value = this.EngKeyBoardList[i][j]; 'K',
else value = this.areaList[i][j]; 'L',
this.$emit('change', value); 'Z',
}, 'X',
// 修改汽车牌键盘的输入模式,中文|英文 'C',
changeCarInputMode() { 'V',
this.abc = !this.abc; 'B',
}, 'N',
// 点击退格键 'M'
backspaceClick() { ];
this.$emit('backspace'); let tmp = [];
 clearInterval(this.timer); //再次清空定时器,防止重复注册定时器 if (this.random) data = this.$u.randomArray(data);
      this.timer = setInterval(() => { tmp[0] = data.slice(0, 10);
    this.$emit('backspace'); tmp[1] = data.slice(10, 20);
      }, 250); tmp[2] = data.slice(20, 30);
}, tmp[3] = data.slice(30, 36);
clearTimer() { return tmp;
clearInterval(this.timer); }
}, },
} methods: {
}; // 点击键盘按钮
</script> carInputClick(i, j) {
let value = '';
<style lang="scss" scoped> // 不同模式,获取不同数组的值
.u-keyboard-grids { if (this.abc) value = this.EngKeyBoardList[i][j];
background: rgb(215, 215, 217); else value = this.areaList[i][j];
padding: 24rpx 0; this.$emit('change', value);
position: relative; },
} // 修改汽车牌键盘的输入模式,中文|英文
changeCarInputMode() {
.u-keyboard-grids-item { this.abc = !this.abc;
display: flex; },
align-items: center; // 点击退格键
justify-content: center; backspaceClick() {
} this.$emit('backspace');
clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
.u-keyboard-grids-btn { this.timer = setInterval(() => {
text-decoration: none; this.$emit('backspace');
width: 62rpx; }, 250);
flex: 0 0 64rpx; },
height: 80rpx; clearTimer() {
display: inline-block; clearInterval(this.timer);
font-size: 36rpx; },
text-align: center; }
line-height: 80rpx; };
background-color: #fff; </script>
margin: 8rpx 5rpx;
border-radius: 8rpx; <style lang="scss" scoped>
box-shadow: 0 2rpx 0rpx #888992; .u-keyboard-grids {
font-weight: 500; background: rgb(215, 215, 217);
} padding: 24rpx 0;
position: relative;
.u-carinput-hover { }
background-color: rgb(185, 188, 195)!important;
} .u-keyboard-grids-item {
display: flex;
.u-keyboard-back { align-items: center;
position: absolute; justify-content: center;
width: 96rpx; }
right: 22rpx;
bottom: 32rpx; .u-keyboard-grids-btn {
height: 80rpx; text-decoration: none;
background-color: rgb(185, 188, 195); width: 62rpx;
display: flex; flex: 0 0 64rpx;
align-items: center; height: 80rpx;
border-radius: 8rpx; display: inline-block;
justify-content: center; font-size: 36rpx;
box-shadow: 0 2rpx 0rpx #888992; text-align: center;
} line-height: 80rpx;
background-color: #fff;
.u-keyboard-change { margin: 8rpx 5rpx;
font-size: 24rpx; border-radius: 8rpx;
box-shadow: 0 2rpx 0rpx #888992; box-shadow: 0 2rpx 0rpx #888992;
position: absolute; font-weight: 500;
width: 96rpx; }
left: 22rpx;
line-height: 1; .u-carinput-hover {
bottom: 32rpx; background-color: rgb(185, 188, 195) !important;
height: 80rpx; }
background-color: #ffffff;
display: flex; .u-keyboard-back {
align-items: center; position: absolute;
border-radius: 8rpx; width: 96rpx;
justify-content: center; right: 22rpx;
} bottom: 32rpx;
height: 80rpx;
.u-keyboard-change .inactive.zh { background-color: rgb(185, 188, 195);
transform: scale(0.85) translateY(-10rpx); display: flex;
} align-items: center;
border-radius: 8rpx;
.u-keyboard-change .inactive.en { justify-content: center;
transform: scale(0.85) translateY(10rpx); box-shadow: 0 2rpx 0rpx #888992;
} }
.u-keyboard-change .active { .u-keyboard-change {
color: rgb(237, 112, 64); font-size: 24rpx;
font-size: 30rpx; box-shadow: 0 2rpx 0rpx #888992;
} position: absolute;
width: 96rpx;
.u-keyboard-change .zh { left: 22rpx;
transform: translateY(-10rpx); line-height: 1;
} bottom: 32rpx;
height: 80rpx;
.u-keyboard-change .en { background-color: #ffffff;
transform: translateY(10rpx); display: flex;
} align-items: center;
border-radius: 8rpx;
justify-content: center;
}
.u-keyboard-change .inactive.zh {
transform: scale(0.85) translateY(-10rpx);
}
.u-keyboard-change .inactive.en {
transform: scale(0.85) translateY(10rpx);
}
.u-keyboard-change .active {
color: rgb(237, 112, 64);
font-size: 30rpx;
}
.u-keyboard-change .zh {
transform: translateY(-10rpx);
}
.u-keyboard-change .en {
transform: translateY(10rpx);
}
</style> </style>
<template> <template>
<view class="u-cell-box"> <view class="u-cell-box">
<view class="u-cell-title" v-if="title" :style="[titleStyle]"> <view class="u-cell-title" v-if="title" :style="[titleStyle]">
{{title}} {{title}}
</view> </view>
<view class="u-cell-item-box" :class="{'u-border-bottom u-border-top': border}"> <view class="u-cell-item-box" :class="{'u-border-bottom u-border-top': border}">
<slot /> <slot />
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { /**
props: { * alertTips 提示
// 分组标题 * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-item
title: { * @tutorial https://www.uviewui.com/components/cell.html
type: String, * @property {String} title 分组标题
default: '' * @property {Boolean} border 是否显示外边框(默认true)
}, * @property {Object} title-style 分组标题的的样式,对象形式,如{'font-size': '24rpx'} 或 {'fontSize': '24rpx'}
// 是否显示分组list上下边框 * @example <u-cell-group title="设置喜好">
border: { */
type: Boolean, export default {
default: true name: "u-cell-group",
}, props: {
// 分组标题的样式,对象形式,注意驼峰属性写法 // 分组标题
// 类似 {'font-size': '24rpx'} 和 {'fontSize': '24rpx'} title: {
titleStyle: { type: String,
type: Object, default: ''
default() { },
return {}; // 是否显示分组list上下边框
} border: {
} type: Boolean,
}, default: true
data() { },
return { // 分组标题的样式,对象形式,注意驼峰属性写法
index: 0, // 类似 {'font-size': '24rpx'} 和 {'fontSize': '24rpx'}
} titleStyle: {
}, type: Object,
provide() { default () {
return { return {};
uCellGroup: this }
} }
}, },
} data() {
</script> return {
index: 0,
<style lang="scss" scoped> }
.u-cell-box { },
width: 100%; provide() {
} return {
uCellGroup: this
.u-cell-title { }
padding: 30rpx 32rpx 10rpx 32rpx; },
font-size: 30rpx; }
text-align: left; </script>
color: $u-tips-color;
} <style lang="scss" scoped>
.u-cell-box {
.u-cell-item-box { width: 100%;
background-color: #FFFFFF; }
}
.u-cell-title {
padding: 30rpx 32rpx 10rpx 32rpx;
font-size: 30rpx;
text-align: left;
color: $u-tips-color;
}
.u-cell-item-box {
background-color: #FFFFFF;
}
</style> </style>
<template> <template>
<view @tap="click" class="u-cell-item-box" :class="{'u-cell-border': itemIndex > 0 }" hover-stay-time="150" :hover-class="hover ? 'u-hover-class' : ''" :style="{ <view @tap="click" class="u-cell-item-box" :class="{'u-cell-border': itemIndex > 0 }" hover-stay-time="150"
backgroundColor: bgColor :hover-class="hover ? 'u-hover-class' : ''" :style="{
}"> backgroundColor: bgColor
<view class="u-cell-content"> }">
<view class="u-icon-wrap" v-if="icon"> <view class="u-cell-content">
<u-icon size="32" :name="icon" class="u-icon"></u-icon> <view class="u-icon-wrap" v-if="icon">
</view> <u-icon size="32" :name="icon" class="u-icon"></u-icon>
<view class="u-icon-wrap"> </view>
<slot name="icon"></slot> <view class="u-icon-wrap">
</view> <slot name="icon"></slot>
<view class="u-cell-title" :style="[titleStyle]"> </view>
<text class="u-title-text" v-if="title">{{title}}</text> <view class="u-cell-title" :style="[titleStyle]">
<slot name="left"></slot> <text class="u-title-text" v-if="title">{{title}}</text>
</view> <slot name="left"></slot>
<view class="u-cell-value" v-if="value"> </view>
<text class="u-value-text" :style="[valueStyle]" v-if="value">{{value}}</text> <view class="u-cell-value" v-if="value">
</view> <text class="u-value-text" :style="[valueStyle]" v-if="value">{{value}}</text>
<view v-else class="u-slot-wrap"> </view>
<slot name="right"></slot> <view v-else class="u-slot-wrap">
</view> <slot name="right"></slot>
<view :style="[arrowStyle]" class="u-icon-wrap"> </view>
<u-icon v-if="arrow" size="26" class="u-arror-right" color="#969799" name="arrow-right"></u-icon> <view :style="[arrowStyle]" class="u-icon-wrap">
</view> <u-icon v-if="arrow" size="26" class="u-arror-right" color="#969799" name="arrow-right"></u-icon>
</view> </view>
<view class="u-cell-label" v-if="label" :style="[labelStyle]"> </view>
{{label}} <view class="u-cell-label" v-if="label" :style="[labelStyle]">
</view> {{label}}
</view> </view>
</template> </view>
</template>
<script>
export default { <script>
props: { /**
// 左侧图标名称(只能uView内置图标),或者图标src * alertTips 提示
icon: { * @description 警告提示,展现需要关注的信息。
type: String, * @tutorial https://www.uviewui.com/components/cell.html
default: '' * @property {String} title 左侧标题
}, * @property {String} icon 左侧图标名,只支持uView内置图标,见Icon 图标
// 左侧标题 * @property {String} value 右侧内容
title: { * @property {String} label 标题下方的描述信息
type: String, * @property {Boolean} border 是否显示每个cell的下边框(默认true)
default: '' * @property {Boolean} hover 是否开启点击反馈,hover-class形式,如果右侧通过slot传递switch进去的话,可以将此值设置为false(默认true)
}, * @property {Boolean} arrow 是否显示右侧箭头(默认true)
// 右侧内容 * @property {Boolean} arrow-direction 箭头方向,可选值(默认right)
value: { * @property {Object} title-style 标题样式,对象形式
type: String, * @property {Object} value-style 右侧内容样式,对象形式
default: '' * @property {Object} label-style 标题下方描述信息的样式,对象形式
}, * @property {String} bg-color 背景颜色(默认#ffffff)
// 标题下方的描述信息 * @property {String Number} index 用于在click事件回调中返回,标识当前是第几个Item
label: { * @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
type: String, */
default: '' export default {
}, name: "u-cell-item",
// 是否显示内边框 props: {
border: { // 左侧图标名称(只能uView内置图标),或者图标src
type: Boolean, icon: {
default: true type: String,
}, default: ''
// 是否开启点击反馈,即点击是cell背景为灰色 },
hover: { // 左侧标题
type: Boolean, title: {
default: true type: String,
}, default: ''
// 是否显示右侧箭头 },
arrow: { // 右侧内容
type: Boolean, value: {
default: true type: String,
}, default: ''
// 右侧箭头方向,可选值:right|up|down,默认为right },
arrowDirection: { // 标题下方的描述信息
type: String, label: {
default: 'right' type: String,
}, default: ''
// 控制标题的样式 },
titleStyle: { // 是否显示内边框
type: Object, border: {
default() { type: Boolean,
return {}; default: true
} },
}, // 是否开启点击反馈,即点击是cell背景为灰色
// 右侧显示内容的样式 hover: {
valueStyle: { type: Boolean,
type: Object, default: true
default() { },
return {}; // 是否显示右侧箭头
} arrow: {
}, type: Boolean,
// 描述信息的样式 default: true
labelStyle: { },
type: Object, // 右侧箭头方向,可选值:right|up|down,默认为right
default() { arrowDirection: {
return {}; type: String,
} default: 'right'
}, },
// 背景颜色 // 控制标题的样式
bgColor: { titleStyle: {
type: String, type: Object,
default: '#ffffff' default () {
}, return {};
// 用于识别被点击的是第几个cell }
index: { },
type: [String, Number], // 右侧显示内容的样式
default: '' valueStyle: {
} type: Object,
}, default () {
inject: ['uCellGroup'], return {};
data() { }
return { },
itemIndex: 0, // 描述信息的样式
} labelStyle: {
}, type: Object,
created() { default () {
this.itemIndex = this.uCellGroup.index++; return {};
}, }
computed: { },
arrowStyle() { // 背景颜色
let style = {}; bgColor: {
if(this.arrowDirection == 'top') style.transform = 'rotate(-90deg)'; type: String,
else if(this.arrowDirection == 'bottom') style.transform = 'rotate(90deg)'; default: '#ffffff'
else style.transform = 'rotate(0deg)'; },
return style; // 用于识别被点击的是第几个cell
} index: {
}, type: [String, Number],
methods: { default: ''
click() { }
this.$emit('click', this.index); },
} inject: ['uCellGroup'],
} data() {
} return {
</script> itemIndex: 0,
}
<style lang="scss" scoped> },
.u-cell-item-box { created() {
padding: 28rpx 32rpx; this.itemIndex = this.uCellGroup.index++;
position: relative; },
} computed: {
arrowStyle() {
.u-cell-border:after { let style = {};
left: 32rpx!important; if (this.arrowDirection == 'top') style.transform = 'rotate(-90deg)';
position: absolute; else if (this.arrowDirection == 'bottom') style.transform = 'rotate(90deg)';
box-sizing: border-box; else style.transform = 'rotate(0deg)';
content: ' '; return style;
pointer-events: none; }
right: 0; },
top: 0; methods: {
border-bottom: 1px solid $u-border-color; click() {
-webkit-transform: scaleY(0.5); this.$emit('click', this.index);
transform: scaleY(0.5); }
} }
}
.u-cell-content { </script>
display: flex;
align-items: center; <style lang="scss" scoped>
} .u-cell-item-box {
padding: 28rpx 32rpx;
.u-cell-title { position: relative;
color: #323233; }
font-size: 30rpx;
flex: 1; .u-cell-border:after {
margin-left: 6rpx; left: 32rpx !important;
text-align: left; position: absolute;
} box-sizing: border-box;
content: ' ';
.u-cell-value { pointer-events: none;
flex: 1; right: 0;
font-size: 26rpx; top: 0;
color: #969799; border-bottom: 1px solid $u-border-color;
text-align: right; -webkit-transform: scaleY(0.5);
} transform: scaleY(0.5);
}
.u-cell-label {
color: #969799; .u-cell-content {
font-size: 26rpx; display: flex;
margin-top: 10rpx; align-items: center;
text-align: left; }
}
.u-cell-title {
.u-slot-wrap { color: #323233;
display: flex; font-size: 30rpx;
align-items: center; flex: 1;
} margin-left: 6rpx;
text-align: left;
// 微信小程序需要额外处理可能通过slot传入badge和switch的问题 }
// 否则无法垂直居中
/* #ifdef MP-WEIXIN */ .u-cell-value {
.u-slot-wrap /deep/ u-badge, flex: 1;
.u-slot-wrap /deep/ u-switch { font-size: 26rpx;
display: flex; color: #969799;
align-items: center; text-align: right;
} }
/* #endif */
.u-cell-label {
.u-icon { color: #969799;
margin-right: 6rpx; font-size: 26rpx;
} margin-top: 10rpx;
text-align: left;
.u-value-text { }
margin-right: 10rpx;
} .u-slot-wrap {
display: flex;
.u-title-text { align-items: center;
margin-right: 10rpx; }
}
</style> // 微信小程序需要额外处理可能通过slot传入badge和switch的问题
\ No newline at end of file // 否则无法垂直居中
/* #ifdef MP-WEIXIN */
.u-slot-wrap /deep/ u-badge,
.u-slot-wrap /deep/ u-switch {
display: flex;
align-items: center;
}
/* #endif */
.u-icon {
margin-right: 6rpx;
}
.u-value-text {
margin-right: 10rpx;
}
.u-title-text {
margin-right: 10rpx;
}
</style>
...@@ -5,6 +5,16 @@ ...@@ -5,6 +5,16 @@
</template> </template>
<script> <script>
/**
* alertTips 提示
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
* @tutorial https://www.uviewui.com/components/checkbox.html
* @property {String Number} max 最多能选中多少个checkbox(默认999)
* @property {Boolean} disabled 是否禁用所有checkbox(默认false)
* @property {String} active-color 选中时的颜色,应用到所有子Checkbox组件(默认#2979ff)
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
* @example <u-checkbox-group></u-checkbox-group>
*/
export default { export default {
props: { props: {
// 最多能选中多少个checkbox // 最多能选中多少个checkbox
......
<template> <template>
<view class="u-checkbox"> <view class="u-checkbox">
<view class="u-checkbox__icon-wrap" @tap="toggle"> <view class="u-checkbox__icon-wrap" @tap="toggle">
<u-icon :class="iconClass" 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>
<view class="u-label-class u-checkbox__label" @tap="onClickLabel"><slot /></view> <view class="u-label-class u-checkbox__label" @tap="onClickLabel">
</view> <slot />
</template> </view>
</view>
<script> </template>
export default {
props: { <script>
// checkbox的名称 /**
name: { * alertTips 提示
type: [String, Number], * @description 该组件需要搭配checkboxGroup组件使用,以便用户进行操作时,获得当前复选框组的选中情况。
default: '' * @tutorial https://www.uviewui.com/components/checkbox.html
}, * @property {String Number} icon-size 图标大小,单位rpx(默认24)
// 形状,square为方形,circle为原型 * @property {String Number} size 组件整体的大小,单位rpx(默认40)
shape: { * @property {String Number} name checkbox组件的标示符
type: String, * @property {String} shape 形状,见官网说明(默认circle)
default: 'square' * @property {Boolean} disabled 是否禁用(默认false)
}, * @property {Boolean} label-disabled 点击文本是否可以操作checkbox(默认true)
// 是否为选中状态 * @property {String} active-color 选中时的颜色,如设置CheckboxGroup的active-color将失效
value: { * @event {Function} change 某个checkbox状态发生变化时触发,回调为一个对象
type: Boolean, * @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
default: false */
}, export default {
// 是否禁用 name: "u-checkbox",
disabled: { props: {
type: Boolean, // checkbox的名称
default: false name: {
}, type: [String, Number],
// 是否禁止点击提示语选中复选框 default: ''
labelDisabled: { },
type: Boolean, // 形状,square为方形,circle为原型
default: false shape: {
}, type: String,
// 选中状态下的颜色,如设置此值,将会覆盖checkboxGroup的activeColor值 default: 'square'
activeColor: { },
type: String, // 是否为选中状态
default: '' value: {
}, type: Boolean,
// 图标的大小,单位rpx default: false
iconSize: { },
type: [String, Number], // 是否禁用
default: 24 disabled: {
}, type: Boolean,
}, default: false
inject: ['checkboxGroup'], },
data() { // 是否禁止点击提示语选中复选框
return { labelDisabled: {
parentDisabled: false, type: Boolean,
}; default: false
}, },
created() { // 选中状态下的颜色,如设置此值,将会覆盖checkboxGroup的activeColor值
this.parentDisabled = this.checkboxGroup.disabled; activeColor: {
this.checkboxGroup.children.push(this); type: String,
}, default: ''
computed: { },
iconStyle() { // 图标的大小,单位rpx
let style = {}; iconSize: {
if (this.checkboxActiveColor && this.value && !this.disabled && !this.parentDisabled) { type: [String, Number],
style.borderColor = this.checkboxActiveColor; default: 24
style.backgroundColor = this.checkboxActiveColor; },
} },
style.width = this.checkboxGroup.size + 'rpx'; inject: ['checkboxGroup'],
style.height = this.checkboxGroup.size + 'rpx'; data() {
return style; return {
}, parentDisabled: false,
iconColor() { };
return this.value ? '#ffffff' : 'transparent'; },
}, created() {
iconClass() { this.parentDisabled = this.checkboxGroup.disabled;
let classs = []; this.checkboxGroup.children.push(this);
classs.push('u-checkbox__icon--' + this.shape); },
if(this.value == true) classs.push('u-checkbox__icon--checked'); computed: {
if(this.disabled || this.parentDisabled) classs.push('u-checkbox__icon--disabled'); iconStyle() {
if(this.value && (this.disabled || this.parentDisabled)) classs.push('u-checkbox__icon--disabled--checked'); let style = {};
return classs; if (this.checkboxActiveColor && this.value && !this.disabled && !this.parentDisabled) {
}, style.borderColor = this.checkboxActiveColor;
// 激活的颜色,可能受checkboxGroup和本组件的activeColor影响 style.backgroundColor = this.checkboxActiveColor;
// 本组件的activeColor值优先 }
checkboxActiveColor() { style.width = this.checkboxGroup.size + 'rpx';
return this.activeColor ? this.activeColor : this.checkboxGroup.activeColor; style.height = this.checkboxGroup.size + 'rpx';
} return style;
}, },
methods: { iconColor() {
onClickLabel() { return this.value ? '#ffffff' : 'transparent';
if (!this.disabled && !this.labelDisabled && !this.parentDisabled) { },
this.setValue(); iconClass() {
} let classs = [];
}, classs.push('u-checkbox__icon--' + this.shape);
toggle() { if (this.value == true) classs.push('u-checkbox__icon--checked');
if (!this.disabled && !this.parentDisabled) { if (this.disabled || this.parentDisabled) classs.push('u-checkbox__icon--disabled');
this.setValue(); if (this.value && (this.disabled || this.parentDisabled)) classs.push('u-checkbox__icon--disabled--checked');
} return classs;
}, },
emitEvent() { // 激活的颜色,可能受checkboxGroup和本组件的activeColor影响
this.$emit('change', {value: this.value, name: this.name}) // 本组件的activeColor值优先
this.checkboxGroup.emitEvent(); checkboxActiveColor() {
}, return this.activeColor ? this.activeColor : this.checkboxGroup.activeColor;
// 设置input的值,这里通过input事件,设置通过v-model绑定的组件的值 }
setValue() { },
// 判断是否超过了可选的最大数量 methods: {
let checkedNum = 0; onClickLabel() {
this.checkboxGroup.children.map(val => { if (!this.disabled && !this.labelDisabled && !this.parentDisabled) {
if(val.value) checkedNum ++; this.setValue();
}) }
// 如果原来为选中状态,那么可以取消 },
if(this.value == true) { toggle() {
this.$emit('input', !this.value); if (!this.disabled && !this.parentDisabled) {
// 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间 this.setValue();
this.$nextTick(function(){ }
this.emitEvent(); },
}) emitEvent() {
} else if(checkedNum < this.checkboxGroup.max && this.value == false) { this.$emit('change', {
// 如果原来为未选中状态,需要选中的数量少于父组件中设置的max值,才可以选中 value: this.value,
this.$emit('input', !this.value); name: this.name
// 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间 })
this.$nextTick(function(){ this.checkboxGroup.emitEvent();
this.emitEvent(); },
}) // 设置input的值,这里通过input事件,设置通过v-model绑定的组件的值
} setValue() {
// 判断是否超过了可选的最大数量
} let checkedNum = 0;
} this.checkboxGroup.children.map(val => {
}; if (val.value) checkedNum++;
</script> })
// 如果原来为选中状态,那么可以取消
<style lang="scss" scoped> if (this.value == true) {
.u-checkbox { this.$emit('input', !this.value);
display: -webkit-flex; // 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
display: flex; this.$nextTick(function() {
-webkit-align-items: center; this.emitEvent();
align-items: center; })
overflow: hidden; } else if (checkedNum < this.checkboxGroup.max && this.value == false) {
-webkit-user-select: none; // 如果原来为未选中状态,需要选中的数量少于父组件中设置的max值,才可以选中
user-select: none; this.$emit('input', !this.value);
} // 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
this.$nextTick(function() {
.u-checkbox__icon-wrap, this.emitEvent();
.u-checkbox__label { })
color: $u-content-color; }
}
}
.u-checkbox__icon-wrap { }
-webkit-flex: none; };
flex: none; </script>
}
<style lang="scss" scoped>
.u-checkbox__icon { .u-checkbox {
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
-webkit-align-items: center; -webkit-align-items: center;
align-items: center; align-items: center;
-webkit-justify-content: center; overflow: hidden;
justify-content: center; -webkit-user-select: none;
box-sizing: border-box; user-select: none;
width: 42rpx; }
height: 42rpx;
color: transparent; .u-checkbox__icon-wrap,
text-align: center; .u-checkbox__label {
transition-property: color, border-color, background-color; color: $u-content-color;
font-size: 20px; }
border: 1px solid #c8c9cc;
transition-duration: 0.2s; .u-checkbox__icon-wrap {
} -webkit-flex: none;
flex: none;
.u-checkbox__icon--circle { }
border-radius: 100%;
} .u-checkbox__icon {
display: -webkit-flex;
.u-checkbox__icon--square { display: flex;
border-radius: 3px; -webkit-align-items: center;
} align-items: center;
-webkit-justify-content: center;
.u-checkbox__icon--checked { justify-content: center;
color: #fff; box-sizing: border-box;
background-color: #2979ff; width: 42rpx;
border-color: #2979ff; height: 42rpx;
} color: transparent;
text-align: center;
.u-checkbox__icon--disabled { transition-property: color, border-color, background-color;
background-color: #ebedf0; font-size: 20px;
border-color: #c8c9cc; border: 1px solid #c8c9cc;
} transition-duration: 0.2s;
}
.u-checkbox__icon--disabled--checked {
color: #c8c9cc!important; .u-checkbox__icon--circle {
} border-radius: 100%;
}
.u-checkbox__label {
word-wrap: break-word; .u-checkbox__icon--square {
margin-left: 10rpx; border-radius: 3px;
margin-right: 18rpx; }
color: $u-content-color;
font-size: 30rpx; .u-checkbox__icon--checked {
} color: #fff;
background-color: #2979ff;
.u-checkbox__label--disabled { border-color: #2979ff;
color: #c8c9cc; }
}
.u-checkbox__icon--disabled {
.u-checkbox__label:empty { background-color: #ebedf0;
margin: 0; border-color: #c8c9cc;
} }
.u-checkbox__icon--disabled--checked {
color: #c8c9cc !important;
}
.u-checkbox__label {
word-wrap: break-word;
margin-left: 10rpx;
margin-right: 18rpx;
color: $u-content-color;
font-size: 30rpx;
}
.u-checkbox__label--disabled {
color: #c8c9cc;
}
.u-checkbox__label:empty {
margin: 0;
}
</style> </style>
<template> <template>
<view class="u-circle-progress" :style="{ <view class="u-circle-progress" :style="{
width: widthPx + 'px', width: widthPx + 'px',
height: widthPx + 'px', height: widthPx + 'px',
backgroundColor: bgColor backgroundColor: bgColor
}"> }">
<canvas class="u-canvas-bg" :canvas-id="elBgId" :style="{ <canvas class="u-canvas-bg" :canvas-id="elBgId" :style="{
width: widthPx + 'px', width: widthPx + 'px',
height: widthPx + 'px' height: widthPx + 'px'
}"></canvas> }"></canvas>
<canvas class="u-canvas" :canvas-id="elId" :style="{ <canvas class="u-canvas" :canvas-id="elId" :style="{
width: widthPx + 'px', width: widthPx + 'px',
height: widthPx + 'px' height: widthPx + 'px'
}"></canvas> }"></canvas>
<slot></slot> <slot></slot>
</view> </view>
</template> </template>
<script> <script>
export default { /**
props: { * alertTips 提示
// 圆环进度百分比值 * @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度条。注意:此组件的percent值只能动态增加,不能动态减少。
percent: { * @tutorial https://www.uviewui.com/components/circleProgress.html
type: Number, * @property {String Number} percent 圆环进度百分比值,为数值类型,0-100
default: 0, * @property {String} inactive-color 圆环的底色,默认为灰色(该值无法动态变更)(默认#ececec)
// 限制值在0到100之间 * @property {String} active-color 圆环激活部分的颜色(该值无法动态变更)(默认#19be6b)
validator: val => { * @property {String Number} width 整个圆环组件的宽度,高度默认等于宽度值,单位rpx(默认200)
return val >= 0 && val <= 100; * @property {String Number} border-width 圆环的边框宽度,单位rpx(默认14)
} * @property {String Number} duration 整个圆环执行一圈的时间,单位ms(默认呢1500)
}, * @property {String} type 如设置,active-color值将会失效
// 底部圆环的颜色(灰色的圆环) * @property {String} bg-color 整个组件背景颜色,默认为白色
inactiveColor: { * @example <u-circle-progress active-color="#2979ff" :percent="80"></u-circle-progress>
type: String, */
default: "#ececec" export default {
}, name: "u-circle-progress",
// 圆环激活部分的颜色 props: {
activeColor: { // 圆环进度百分比值
type: String, percent: {
default: '#19be6b' type: Number,
}, default: 0,
// 圆环线条的宽度,单位rpx // 限制值在0到100之间
borderWidth: { validator: val => {
type: [Number, String], return val >= 0 && val <= 100;
default: 14 }
}, },
// 整个圆形的宽度,单位rpx // 底部圆环的颜色(灰色的圆环)
width: { inactiveColor: {
type: [Number, String], type: String,
default: 200 default: "#ececec"
}, },
// 整个圆环执行一圈的时间,单位ms // 圆环激活部分的颜色
duration: { activeColor: {
type: [Number, String], type: String,
default: 1500 default: '#19be6b'
}, },
// 主题类型 // 圆环线条的宽度,单位rpx
type: { borderWidth: {
type: String, type: [Number, String],
default: '' default: 14
}, },
// 整个圆环进度区域的背景色 // 整个圆形的宽度,单位rpx
bgColor: { width: {
type: String, type: [Number, String],
default: "#ffffff" default: 200
} },
}, // 整个圆环执行一圈的时间,单位ms
data() { duration: {
return { type: [Number, String],
elBgId: this.$u.guid(), default: 1500
elId: this.$u.guid(), },
ctxBg: '', // 背景canvas实例 // 主题类型
ctx: '', // 前景(激活时候)canvas的实例 type: {
count: 0, // 计数器 type: String,
timer: null, // 定时器 default: ''
times: 0, // 总共要执行的动画次数,setInterval的次数 },
time: 0, // 执行整个动画的时间 // 整个圆环进度区域的背景色
widthPx: uni.upx2px(this.width), // 转成px后的整个组件的背景宽度 bgColor: {
borderWidthPx: uni.upx2px(this.borderWidth), // 转成px后的圆环的宽度 type: String,
mode: 'more', // more-percent增加,less-percent减少 default: "#ffffff"
} }
}, },
watch: { data() {
percent: { return {
immediate: true, elBgId: this.$u.guid(),
handler(nVal, oVal = 0) { elId: this.$u.guid(),
this.mode = nVal > oVal ? 'more' : 'less'; ctxBg: '', // 背景canvas实例
this.times = Math.ceil(nVal * 3.6); ctx: '', // 前景(激活时候)canvas的实例
this.time = Math.ceil(this.duration / 360 * this.times); count: 0, // 计数器
setTimeout(() => { timer: null, // 定时器
this.countInterval(); times: 0, // 总共要执行的动画次数,setInterval的次数
}, 50) time: 0, // 执行整个动画的时间
} widthPx: uni.upx2px(this.width), // 转成px后的整个组件的背景宽度
} borderWidthPx: uni.upx2px(this.borderWidth), // 转成px后的圆环的宽度
}, mode: 'more', // more-percent增加,less-percent减少
computed: { }
// 有type主题时,优先起作用 },
circleColor() { watch: {
if(['success', 'error', 'info', 'primary', 'warning'].indexOf(this.type) >= 0) return this.$u.color[this.type]; percent: {
else return this.activeColor; immediate: true,
} handler(nVal, oVal = 0) {
}, this.mode = nVal > oVal ? 'more' : 'less';
mounted() { this.times = Math.ceil(nVal * 3.6);
this.ctxBg = uni.createCanvasContext(this.elBgId, this); this.time = Math.ceil(this.duration / 360 * this.times);
this.ctx = uni.createCanvasContext(this.elId, this); setTimeout(() => {
// 在h5端,必须要做一点延时才起作用,this.$nextTick()无效(HX2.4.7) this.countInterval();
setTimeout(() => { }, 50)
this.drawProgressBg(); }
}, 50) }
}, },
methods: { computed: {
drawProgressBg() { // 有type主题时,优先起作用
this.ctxBg.setLineWidth(this.borderWidthPx); // 设置圆环宽度 circleColor() {
this.ctxBg.setStrokeStyle(this.inactiveColor); // 线条颜色 if (['success', 'error', 'info', 'primary', 'warning'].indexOf(this.type) >= 0) return this.$u.color[this.type];
this.ctxBg.setLineCap('round'); // 圆环端点的形状为圆形 else return this.activeColor;
this.ctxBg.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); mounted() {
this.ctxBg.stroke(); // 对路径进行描绘 this.ctxBg = uni.createCanvasContext(this.elBgId, this);
this.ctxBg.draw(); this.ctx = uni.createCanvasContext(this.elId, this);
}, // 在h5端,必须要做一点延时才起作用,this.$nextTick()无效(HX2.4.7)
drawCircle(step) { setTimeout(() => {
this.ctx.setLineWidth(this.borderWidthPx); this.drawProgressBg();
this.ctx.setStrokeStyle(this.circleColor); }, 50)
this.ctx.setLineCap('round'); },
this.ctx.beginPath(); methods: {
// 参数step 为绘制的圆环周长,从0到2为一周 。 -Math.PI / 2 将起始角设在12点钟位置 ,结束角 通过改变 step 的值确定 drawProgressBg() {
if(this.mode == 'more') { this.ctxBg.setLineWidth(this.borderWidthPx); // 设置圆环宽度
this.ctx.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, -Math.PI / 2, step * this.ctxBg.setStrokeStyle(this.inactiveColor); // 线条颜色
Math.PI - Math.PI / 2, false); this.ctxBg.setLineCap('round'); // 圆环端点的形状为圆形
} else { this.ctxBg.beginPath(); // 开始描绘路径
this.ctx.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, -Math.PI / 2, Math.PI / 2 - step * // 设置一个原点(110,110),半径为100的圆的路径到当前路径
Math.PI, false); this.ctxBg.arc(this.widthPx / 2, this.widthPx / 2, this.widthPx / 2 - this.borderWidthPx / 2 - 1, 0, 2 * Math.PI,
} false);
this.ctx.stroke(); this.ctxBg.stroke(); // 对路径进行描绘
this.ctx.draw() this.ctxBg.draw();
}, },
countInterval() { drawCircle(step) {
this.countTimer = setInterval(() => { this.ctx.setLineWidth(this.borderWidthPx);
if (this.count <= this.times) { this.ctx.setStrokeStyle(this.circleColor);
// 全一个圆时候,值为2,这里求出每一份的值为2/360 this.ctx.setLineCap('round');
this.drawCircle(this.count * 2 / 360); this.ctx.beginPath();
this.count++; // 参数step 为绘制的圆环周长,从0到2为一周 。 -Math.PI / 2 将起始角设在12点钟位置 ,结束角 通过改变 step 的值确定
} else { if (this.mode == 'more') {
clearInterval(this.countTimer); 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);
}, Math.ceil(this.duration / 360)); // 总过渡时间分为360份,这里为每一份的时间 } 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);
</script> }
this.ctx.stroke();
<style lang="scss" scoped> this.ctx.draw()
.u-circle-progress { },
position: relative; countInterval() {
display: inline-flex; this.countTimer = setInterval(() => {
align-items: center; if (this.count <= this.times) {
justify-content: center; // 全一个圆时候,值为2,这里求出每一份的值为2/360
} this.drawCircle(this.count * 2 / 360);
this.count++;
.u-canvas-bg { } else {
position: absolute; clearInterval(this.countTimer);
} }
}, Math.ceil(this.duration / 360)); // 总过渡时间分为360份,这里为每一份的时间
.u-canvas { },
position: absolute; }
} }
</script>
<style lang="scss" scoped>
.u-circle-progress {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
}
.u-canvas-bg {
position: absolute;
}
.u-canvas {
position: absolute;
}
</style> </style>
<template> <template>
<view class="u-collapse-item"> <view class="u-collapse-item">
<view <view class="u-collapse-head" @tap.stop="headClick" hover-class="u-hover-class" :style="[headStyle]">
class="u-collapse-head" <view class="u-collapse-title u-line-1" :style="[{ textAlign: align ? align : 'left' },
@tap.stop="headClick" isShow && activeStyle && !arrow ? activeStyle : '']">
hover-class="u-hover-class" {{ title }}
:style="[headStyle]" </view>
> <view class="u-icon-wrap">
<view class="u-collapse-title u-line-1" <u-icon v-if="arrow" :color="arrowColor ? arrowColor : $u.color.tipsColor" :class="{ 'u-arrow-down-icon-active': isShow }"
:style="[{ textAlign: align ? align : 'left' }, class="u-arrow-down-icon" name="arrow-down"></u-icon>
isShow && activeStyle && !arrow ? activeStyle : '']" </view>
> </view>
{{ title }} <view class="u-collapse-body" :style="[{
</view> height: isShow ? height + 'px' : '0'
<view class="u-icon-wrap"> }, bodyStyle]">
<u-icon <view class="u-collapse-content" :id="elId">
v-if="arrow" <slot></slot>
:color="arrowColor ? arrowColor : $u.color.tipsColor" </view>
:class="{ 'u-arrow-down-icon-active': isShow }" </view>
class="u-arrow-down-icon" </view>
name="arrow-down" </template>
></u-icon>
</view> <script>
</view> /**
<view * alertTips 提示
class="u-collapse-body" * @description 通过折叠面板收纳内容区域(搭配u-collapse使用)
:style="[{ * @tutorial https://www.uviewui.com/components/collapse.html
height: isShow ? height + 'px' : '0' * @property {String} title 面板标题
}, bodyStyle]" * @property {String Number} index 主要用于事件的回调,标识那个Item被点击
> * @property {Boolean} disabled 面板是否可以打开或收起(默认false)
<view class="u-collapse-content" :id="elId"><slot></slot></view> * @property {Boolean} open 设置某个面板的初始状态是否打开(默认false)
</view> * @property {String Number} name 唯一标识符,如不设置,默认用当前collapse-item的索引值
</view> * @property {String} align 标题的对齐方式(默认left)
</template> * @property {Object} active-style 不显示箭头时,可以添加当前选择的collapse-item活动样式,对象形式
* @event {Function} change 某个item被打开或者收起时触发
<script> * @example <u-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</u-collapse-item>
export default { */
props: { export default {
// 标题 name: "u-collapse-item",
title: { props: {
type: String, // 标题
default: '' title: {
}, type: String,
// 标题的对齐方式 default: ''
align: { },
type: String, // 标题的对齐方式
default: 'left' align: {
}, type: String,
// 是否可以点击收起 default: 'left'
disabled: { },
type: Boolean, // 是否可以点击收起
default: false disabled: {
}, type: Boolean,
// collapse显示与否 default: false
open: { },
type: Boolean, // collapse显示与否
default: false open: {
}, type: Boolean,
// 唯一标识符 default: false
name: { },
type: [Number, String], // 唯一标识符
default: '' name: {
}, type: [Number, String],
//活动样式 default: ''
activeStyle: { },
type: Object, //活动样式
default() { activeStyle: {
return {} type: Object,
} default () {
}, return {}
// 标识当前为第几个 }
index: { },
type: [String, Number], // 标识当前为第几个
default: '' index: {
} type: [String, Number],
}, default: ''
inject: ['uCollapse'], }
data() { },
return { inject: ['uCollapse'],
isShow: false, data() {
elId: this.$u.guid(), return {
height: 0, // body内容的高度 isShow: false,
headStyle: {}, // 头部样式,对象形式 elId: this.$u.guid(),
bodyStyle: {}, // 主体部分样式 height: 0, // body内容的高度
arrowColor: '' headStyle: {}, // 头部样式,对象形式
}; bodyStyle: {}, // 主体部分样式
}, arrowColor: ''
mounted() { };
this.$nextTick(() => { },
this.queryRect(); mounted() {
}); this.$nextTick(() => {
}, this.queryRect();
watch: { });
open(val) { },
this.isShow = val; watch: {
} open(val) {
}, this.isShow = val;
computed: { }
arrow() { },
return this.uCollapse.arrow; computed: {
} arrow() {
}, return this.uCollapse.arrow;
created() { }
this.isShow = this.open; },
this.nameSync = this.name ? this.name : this.uCollapse.childrens.length; created() {
this.uCollapse.childrens.push(this); this.isShow = this.open;
this.headStyle = this.uCollapse.headStyle; this.nameSync = this.name ? this.name : this.uCollapse.childrens.length;
this.bodyStyle = this.uCollapse.bodyStyle; this.uCollapse.childrens.push(this);
this.arrowColor = this.uCollapse.arrowColor; this.headStyle = this.uCollapse.headStyle;
}, this.bodyStyle = this.uCollapse.bodyStyle;
methods: { this.arrowColor = this.uCollapse.arrowColor;
// 点击collapsehead头部 },
headClick() { methods: {
if (this.disabled) return; // 点击collapsehead头部
if (this.uCollapse.accordion == true) { headClick() {
this.uCollapse.childrens.map(val => { if (this.disabled) return;
// 自身不设置为false,因为后面有this.isShow = !this.isShow;处理了 if (this.uCollapse.accordion == true) {
if (this != val) { this.uCollapse.childrens.map(val => {
val.isShow = false; // 自身不设置为false,因为后面有this.isShow = !this.isShow;处理了
} if (this != val) {
}); val.isShow = false;
} }
});
this.isShow = !this.isShow; }
// 触发本组件的事件
this.$emit('change', { this.isShow = !this.isShow;
index: this.index, // 触发本组件的事件
show: this.isShow this.$emit('change', {
}) index: this.index,
show: this.isShow
// 只有在打开时才发出事件 })
if (this.isShow) this.uCollapse.onChange();
this.$forceUpdate(); // 只有在打开时才发出事件
}, if (this.isShow) this.uCollapse.onChange();
// 查询内容高度 this.$forceUpdate();
queryRect() { },
const query = uni.createSelectorQuery().in(this); // 查询内容高度
query queryRect() {
.select('#' + this.elId) const query = uni.createSelectorQuery().in(this);
.boundingClientRect(data => { query
if (!data.height) { .select('#' + this.elId)
setTimeout(() => { .boundingClientRect(data => {
this.queryRect(); if (!data.height) {
}, 10); setTimeout(() => {
return; this.queryRect();
} }, 10);
this.height = data.height; return;
}) }
.exec(); this.height = data.height;
} })
} .exec();
}; }
</script> }
};
<style lang="scss" scoped> </script>
.u-collapse-head {
position: relative; <style lang="scss" scoped>
display: flex; .u-collapse-head {
justify-content: space-between; position: relative;
align-items: center; display: flex;
color: $u-main-color; justify-content: space-between;
} align-items: center;
color: $u-main-color;
.u-collapse-title { }
flex: 1;
overflow: hidden; .u-collapse-title {
margin-right: 14rpx; flex: 1;
font-size: 30rpx; overflow: hidden;
color: $u-main-color; margin-right: 14rpx;
line-height: 1; font-size: 30rpx;
padding: 24rpx 0; color: $u-main-color;
text-align: left; line-height: 1;
} padding: 24rpx 0;
text-align: left;
.u-arrow-down-icon { }
transition: all 0.3s;
margin-right: 24rpx; .u-arrow-down-icon {
} transition: all 0.3s;
margin-right: 24rpx;
.u-arrow-down-icon-active { }
transform: rotate(180deg);
transform-origin: center center; .u-arrow-down-icon-active {
} transform: rotate(180deg);
transform-origin: center center;
.u-collapse-body { }
overflow: hidden;
transition: all 0.3s; .u-collapse-body {
} overflow: hidden;
transition: all 0.3s;
.u-collapse-content { }
overflow: hidden;
font-size: 28rpx; .u-collapse-content {
color: $u-tips-color; overflow: hidden;
text-align: left; font-size: 28rpx;
} color: $u-tips-color;
text-align: left;
}
</style> </style>
<template> <template>
<view class="u-collapse"> <view class="u-collapse">
<slot /> <slot />
</view> </view>
</template> </template>
<script> <script>
/**
* alertTips 提示
* @description 通过折叠面板收纳内容区域
* @tutorial https://www.uviewui.com/components/collapse.html
* @property {Boolean} accordion 是否手风琴模式(默认true)
* @property {Boolean} arrow 是否显示标题右侧的箭头(默认true)
* @property {String} arrow-color 标题右侧箭头的颜色(默认#909399)
* @property {String} head-bg-color 标题的背景颜色(默认#ffffff)
* @property {String} body-bg-color 主体内容的背景颜色(默认#ffffff)
* @event {Function} change 当前激活面板展开时触发(如果是手风琴模式,参数activeNames类型为String,否则为Array)
* @example <u-collapse></u-collapse>
*/
export default { export default {
props: { name:"u-collapse",
// 是否手风琴模式 props: {
accordion: { // 是否手风琴模式
type: Boolean, accordion: {
default: true type: Boolean,
}, default: true
// 头部的样式 },
headStyle: { // 头部的样式
type: Object, headStyle: {
default() { type: Object,
return {} default () {
} return {}
}, }
// 主体的样式 },
bodyStyle: { // 主体的样式
type: Object, bodyStyle: {
default() { type: Object,
return {} default () {
} return {}
}, }
// 是否显示右侧的箭头 },
arrow: { // 是否显示右侧的箭头
type: Boolean, arrow: {
default: true type: Boolean,
}, default: true
// 箭头的颜色 },
arrowColor: { // 箭头的颜色
type: String, arrowColor: {
default: '' type: String,
}, default: ''
}, },
provide() { },
return { provide() {
uCollapse: this return {
} uCollapse: this
}, }
created() { },
this.childrens = [] created() {
}, this.childrens = []
data() { },
return { data() {
return {
}
}, }
methods: { },
// collapse item被点击,由collapse item调用父组件方法 methods: {
onChange() { // collapse item被点击,由collapse item调用父组件方法
let activeItem = []; onChange() {
this.childrens.forEach((vm, index) => { let activeItem = [];
if (vm.isShow) { this.childrens.forEach((vm, index) => {
activeItem.push(vm.nameSync); if (vm.isShow) {
} activeItem.push(vm.nameSync);
}) }
// 如果是手风琴模式,只有一个匹配结果,也即activeItem长度为1,将其转为字符串 })
if(this.accordion) activeItem = activeItem.join(''); // 如果是手风琴模式,只有一个匹配结果,也即activeItem长度为1,将其转为字符串
this.$emit('change', activeItem); if (this.accordion) activeItem = activeItem.join('');
} this.$emit('change', activeItem);
} }
} }
</script> }
</script>
<style lang="scss" scoped>
<style lang="scss" scoped>
</style> </style>
<template> <template>
<view class="u-countdown"> <view class="u-countdown">
<view class="u-countdown-item" :style="[itemStyle]" v-if="showDays"> <view class="u-countdown-item" :style="[itemStyle]" v-if="showDays">
<view class="u-countdown-time" :style="[letterStyle]"> <view class="u-countdown-time" :style="[letterStyle]">
{{ d }} {{ d }}
</view> </view>
</view> </view>
<view <view class="u-countdown-colon" :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
class="u-countdown-colon" v-if="showDays">
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}" {{ separator == 'colon' ? ':' : '' }}
v-if="showDays" </view>
> <view class="u-countdown-item" :style="[itemStyle]" v-if="showHours">
{{ separator == 'colon' ? ':' : '' }} <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
</view> {{ h }}
<view class="u-countdown-item" :style="[itemStyle]" v-if="showHours"> </view>
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}"> </view>
{{ h }} <view class="u-countdown-colon" :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
</view> v-if="showHours">
</view> {{ separator == 'colon' ? ':' : '' }}
<view </view>
class="u-countdown-colon" <view class="u-countdown-item" :style="[itemStyle]" v-if="showMinutes">
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}" <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
v-if="showHours" {{ i }}
> </view>
{{ separator == 'colon' ? ':' : '' }} </view>
</view> <view class="u-countdown-colon" :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
<view class="u-countdown-item" :style="[itemStyle]" v-if="showMinutes"> v-if="showMinutes">
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}"> {{ separator == 'colon' ? ':' : '' }}
{{ i }} </view>
</view> <view class="u-countdown-item" :style="[itemStyle]" v-if="showSeconds">
</view> <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
<view {{ s }}
class="u-countdown-colon" </view>
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}" </view>
v-if="showMinutes" <view class="u-countdown-colon" :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
> v-if="showSeconds && separator == 'zh'">
{{ separator == 'colon' ? ':' : '' }}
</view> </view>
<view class="u-countdown-item" :style="[itemStyle]" v-if="showSeconds"> </view>
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}"> </template>
{{ s }}
</view> <script>
</view> /**
<view * alertTips 提示
class="u-countdown-colon" * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}" * @tutorial https://www.uviewui.com/components/countDown.html
v-if="showSeconds && separator == 'zh'" * @property {String Number} timestamp 倒计时,单位为秒
> * @property {Boolean} autopaly 是否自动开始倒计时,如果为false,需手动调用开始方法。见官网说明(默认true)
* @property {String} separator 分隔符,colon为英文冒号,zh为中文(默认colon)
</view> * @property {String Number} separator-size 分隔符的字体大小,单位rpx(默认30)
</view> * @property {String} separator-color 分隔符的颜色(默认#303133)
</template> * @property {String Number} font-size 倒计时字体大小,单位rpx(默认30)
* @property {Boolean} show-border 是否显示倒计时数字的边框(默认false)
<script> * @property {String} border-color 数字边框的颜色(默认#303133)
export default { * @property {String} bg-color 倒计时数字的背景颜色(默认#ffffff)
props: { * @property {String} color 倒计时数字的颜色(默认#303133)
// 倒计时的时间,秒为单位 * @property {String} height 数字高度值(宽度等同此值),设置边框时看情况是否需要设置此值,单位rpx(默认auto)
timestamp: { * @property {Boolean} show-days 是否显示倒计时的"天"部分(默认true)
type: [Number, String], * @property {Boolean} show-hours 是否显示倒计时的"时"部分(默认true)
default: 0 * @property {Boolean} show-minutes 是否显示倒计时的"分"部分(默认true)
}, * @property {Boolean} show-seconds 是否显示倒计时的"秒"部分(默认true)
// 是否自动开始倒计时 * @event {Function} end 倒计时结束
autopaly: { * @example <u-count-down ref="uCountDown" :timestamp="86400" :autoplay="false"></u-count-down>
type: Boolean, */
default: true export default {
}, name:"u-count-down",
// 用英文冒号(colon)或者中文(zh)当做分隔符,false的时候为中文,如:"11:22"或"11时22秒" props: {
separator: { // 倒计时的时间,秒为单位
type: String, timestamp: {
default: 'colon' type: [Number, String],
}, default: 0
// 分隔符的大小,单位rpx },
separatorSize: { // 是否自动开始倒计时
type: [Number, String], autopaly: {
default: 30 type: Boolean,
}, default: true
// 分隔符颜色 },
separatorColor: { // 用英文冒号(colon)或者中文(zh)当做分隔符,false的时候为中文,如:"11:22"或"11时22秒"
type: String, separator: {
default: "#303133" type: String,
}, default: 'colon'
// 字体颜色 },
color: { // 分隔符的大小,单位rpx
type: String, separatorSize: {
default: '#303133' type: [Number, String],
}, default: 30
// 字体大小,单位rpx },
fontSize: { // 分隔符颜色
type: [Number, String], separatorColor: {
default: 30 type: String,
}, default: "#303133"
// 背景颜色 },
bgColor: { // 字体颜色
type: String, color: {
default: '#fff' type: String,
}, default: '#303133'
// 数字框高度,单位rpx },
height: { // 字体大小,单位rpx
type: [Number, String], fontSize: {
default: 'auto' type: [Number, String],
}, default: 30
// 是否显示数字框 },
showBorder: { // 背景颜色
type: Boolean, bgColor: {
default: false type: String,
}, default: '#fff'
// 边框颜色 },
borderColor: { // 数字框高度,单位rpx
type: String, height: {
default: '#303133' type: [Number, String],
}, default: 'auto'
// 是否显示秒 },
showSeconds: { // 是否显示数字框
type: Boolean, showBorder: {
default: true type: Boolean,
}, default: false
// 是否显示分钟 },
showMinutes: { // 边框颜色
type: Boolean, borderColor: {
default: true type: String,
}, default: '#303133'
// 是否显示小时 },
showHours: { // 是否显示秒
type: Boolean, showSeconds: {
default: true type: Boolean,
}, default: true
// 是否显示“天” },
showDays: { // 是否显示分钟
type: Boolean, showMinutes: {
default: true type: Boolean,
}, default: true
}, },
watch: { // 是否显示小时
// 监听时间戳的变化 showHours: {
timestamp(newVal, oldVal) { type: Boolean,
// 如果倒计时间发生变化,清除定时器,重新开始倒计时 default: true
clearInterval(this.timer); },
this.start(); // 是否显示“天”
} showDays: {
}, type: Boolean,
data() { default: true
return { },
d: '00', // 天的默认值 },
h: '00', // 小时的默认值 watch: {
i: '00', // 分钟的默认值 // 监听时间戳的变化
s: '00', // 秒的默认值 timestamp(newVal, oldVal) {
timer: null // 定时器 // 如果倒计时间发生变化,清除定时器,重新开始倒计时
}; clearInterval(this.timer);
}, this.start();
computed: { }
// 倒计时item的样式,item为分别的时分秒部分的数字 },
itemStyle() { data() {
let style = {}; return {
if(this.height) { d: '00', // 天的默认值
style.height = this.height + 'rpx'; h: '00', // 小时的默认值
style.width = this.height + 'rpx'; i: '00', // 分钟的默认值
} s: '00', // 秒的默认值
if(this.showBorder) { timer: null // 定时器
style.borderStyle = 'solid'; };
style.borderColor = this.borderColor; },
style.borderWidth = '1px'; computed: {
} // 倒计时item的样式,item为分别的时分秒部分的数字
if(this.bgColor) { itemStyle() {
style.backgroundColor = this.bgColor; let style = {};
} if (this.height) {
return style; style.height = this.height + 'rpx';
}, style.width = this.height + 'rpx';
// 倒计时数字的样式 }
letterStyle() { if (this.showBorder) {
let style = {}; style.borderStyle = 'solid';
if(this.fontSize) style.fontSize = this.fontSize + 'rpx'; style.borderColor = this.borderColor;
if(this.color) style.color = this.color; style.borderWidth = '1px';
return style; }
} if (this.bgColor) {
}, style.backgroundColor = this.bgColor;
mounted() { }
// 如果自动倒计时 return style;
this.autopaly && this.timestamp && this.start(); },
}, // 倒计时数字的样式
methods: { letterStyle() {
// 倒计时 let style = {};
start() { if (this.fontSize) style.fontSize = this.fontSize + 'rpx';
if (this.timestamp <= 0) return; if (this.color) style.color = this.color;
let seconds = Number(this.timestamp); return style;
this.formatTime(seconds); }
this.timer = setInterval(() => { },
seconds--; mounted() {
if (seconds < 0) { // 如果自动倒计时
return this.end(); this.autopaly && this.timestamp && this.start();
} },
this.formatTime(seconds); methods: {
}, 1000); // 倒计时
}, start() {
// 格式化时间 if (this.timestamp <= 0) return;
formatTime(seconds) { let seconds = Number(this.timestamp);
// 小于等于0的话,结束倒计时 this.formatTime(seconds);
seconds <= 0 && this.end(); this.timer = setInterval(() => {
let [day, hour, minute, second] = [0, 0, 0, 0]; seconds--;
day = Math.floor(seconds / (60 * 60 * 24)); if (seconds < 0) {
hour = Math.floor(seconds / (60 * 60)) - day * 24; return this.end();
minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60; }
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60; this.formatTime(seconds);
// 如果小于10,在前面补上一个"0" }, 1000);
hour = hour < 10 ? '0' + hour : hour; },
minute = minute < 10 ? '0' + minute : minute; // 格式化时间
second = second < 10 ? '0' + second : second; formatTime(seconds) {
this.d = day; // 小于等于0的话,结束倒计时
this.h = hour; seconds <= 0 && this.end();
this.i = minute; let [day, hour, minute, second] = [0, 0, 0, 0];
this.s = second; day = Math.floor(seconds / (60 * 60 * 24));
}, hour = Math.floor(seconds / (60 * 60)) - day * 24;
// 停止倒计时 minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60;
end() { second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
// 清除定时器 // 如果小于10,在前面补上一个"0"
clearInterval(this.timer); hour = hour < 10 ? '0' + hour : hour;
this.timer = null; minute = minute < 10 ? '0' + minute : minute;
this.$emit('end', {}); second = second < 10 ? '0' + second : second;
} this.d = day;
}, this.h = hour;
beforeDestroy() { this.i = minute;
clearInterval(this.timer); this.s = second;
this.timer = null; },
} // 停止倒计时
}; end() {
</script> // 清除定时器
clearInterval(this.timer);
<style scoped lang="scss"> this.timer = null;
.u-countdown { this.$emit('end', {});
display: inline-flex; }
align-items: center; },
} beforeDestroy() {
clearInterval(this.timer);
.u-countdown-item { this.timer = null;
display: flex; }
align-items: center; };
justify-content: center; </script>
padding: 2rpx;
border-radius: 6rpx; <style scoped lang="scss">
white-space: nowrap; .u-countdown {
transform: translateZ(0); display: inline-flex;
} align-items: center;
}
.u-countdown-time {
margin: 0; .u-countdown-item {
padding: 0; display: flex;
line-height: 1; align-items: center;
} justify-content: center;
padding: 2rpx;
.u-countdown-colon { border-radius: 6rpx;
display: flex; white-space: nowrap;
justify-content: center; transform: translateZ(0);
padding: 0 5rpx; }
line-height: 1;
align-items: center; .u-countdown-time {
padding-bottom: 4rpx; margin: 0;
} padding: 0;
line-height: 1;
.u-countdown-scale { }
transform: scale(0.9);
transform-origin: center center; .u-countdown-colon {
} display: flex;
justify-content: center;
padding: 0 5rpx;
line-height: 1;
align-items: center;
padding-bottom: 4rpx;
}
.u-countdown-scale {
transform: scale(0.9);
transform-origin: center center;
}
</style> </style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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